12

これが私がやろうとしていることです:

isPrime :: Int -> Bool
isPrime x = all (\y -> x `mod` y /= 0) [3, 5..floor(sqrt x)]

(2で割った値をチェックしていないことはわかっていますが、無視してください。)次のようになります。

No instance for (Floating Int)
  arising from a use of `sqrt'
Possible fix: add an instance declaration for (Floating Int)
In the first argument of `floor', namely `(sqrt x)'
In the expression: floor (sqrt x)
In the second argument of `all', namely `[3, 5 .. floor (sqrt x)]'

私は文字通り何時間もかけて、sqrtのいくつかのバリアントを使用してこのリストを作成するために考えられるすべてのことを試みてきました。

intSqrt :: Int -> Int
intSqrt x = floor (sqrt (x + 0.0))

(sqrt 500)は正常に機能しているようですが、(sqrt x)はxが浮動小数点であると主張しており(なぜ?)、Intを実数に変換するために見つけることができる関数はありません(なぜ?)。

素数性をテストする方法は必要ありません。これを修正する方法を理解したいと思います。なんでこんなに難しいの?

4

2 に答える 2

21

他のほとんどの言語とは異なり、Haskellは整数型と浮動小数点型を厳密に区別し、暗黙的に一方を他方に変換しません。明示的に変換する方法については、こちらをご覧ください。例もありsqrtます:-)

これの根本的な理由は、暗黙の変換とHaskelの(かなり複雑ですが非常にクールな)クラスシステムの組み合わせにより、型の再構築が非常に困難になるためです。おそらく、マシンで実行できるレベルを超えて拡張されます。言語設計者は、算術用の型クラスを取得することは、変換を明示的に指定しなければならないコストに見合う価値があると感じました。

于 2011-08-09T19:59:25.377 に答える
19

あなたの問題は、あなたはそれをさまざまな方法で修正しようとしましたが、あなたは何かをしようとしなかったということですx。それはまさにあなたの問題が存在するところです。次のタイプを見てみましょうsqrt

Prelude> :t sqrt
sqrt :: (Floating a) => a -> a

一方、xはでありInt、GHCiにについての情報を求めると、次のようFloatingになります。

Prelude> :info Floating
class (Fractional a) => Floating a where
  pi :: a
  <...snip...>
  acosh :: a -> a
    -- Defined in GHC.Float
instance Floating Float -- Defined in GHC.Float
instance Floating Double -- Defined in GHC.Float

したがって、 sとsのタイプのみFloatingです。他の方向と同じように、をに変換する方法が必要です。このようなタイプの質問があるときはいつでも、タイプを検索するHaskell検索エンジンであるHoogleに尋ねることができます。残念ながら、を検索すると、お粗末な結果が得られます。しかし、私たちが探しているものをリラックスさせたらどうなるでしょうか?を検索すると、ほぼ正確に必要な関数があることがわかります。そして、型をまで緩和すると、関数があることがわかります。FloatDoubleIntDoublefloor :: (RealFrac a, Integral b) => a -> bInt -> DoubleInteger -> DoublefromInteger :: Num a => Integer -> a(Integral a, Num b) => a -> bfromIntegral :: (Integral a, Num b) => a -> b

したがって、整数の平方根を計算するには、を使用するfloor . sqrt $ fromIntegral xか、を使用します

isqrt :: Integral i => i -> i
isqrt = floor . sqrt . fromIntegral

sqrtあなたは;の出力のために正しい方向で問題について考えていました。浮動小数点数を返しましたが、整数が必要でした。ただし、Haskellにはサブタイピングや暗黙のキャストの概念がないため、入力も変更する必要がありsqrtます。

他の懸念事項のいくつかに対処するには:

intSqrt :: Int -> Int
intSqrt x = floor (sqrt (x + 0.0))

あなたはこれを「ナンセンス」と呼んでいるので、それが機能することを期待していないことは明らかですが、なぜそうではないのですか?問題は、(+)タイプがあるNum a => a -> a -> aことです。同じタイプのものを2つしか追加できません。これは、5×5の実数行列に複素数を追加できないことを意味するため、一般的には適切です。ただし、0.0のインスタンスである必要があるため、Fractionalに追加することはできませんx :: Int

(sqrt 500)は正常に機能しているようです…</ p>

500のタイプが期待したものではないため、これは機能します。信頼できる仲間のGHCiに聞いてみましょう。

Prelude> :t 500
500 :: (Num t) => t

実際、すべての整数リテラルにはこのタイプがあります。これらは任意の種類の数値にすることができます。これは、Numクラスに関数が含まれているために機能しますfromInteger :: Integer -> a。したがって、あなたが書いたとき、GHCはそれが満たされる必要がsqrt 500あることに気づきました(そしてそれはデフォルトのルールのおかげでそのような数値タイプを暗黙的に選択します)。同様に、上記はの関数のおかげでタイプがあります。500500 :: (Num t, Floating t) => tDouble0.0Fractional t => tFractionalfromRational :: Rational -> a

…しかし(sqrt x)はxがフローティングであると主張しています…</ p>

のタイプを見る上記を参照してくださいsqrt

…そして、Intを実数に変換するために見つけることができる関数はありません…。

さて、あなたは今それを持っています:fromIntegral。なぜあなたがそれを見つけられなかったのか分かりません。どうやらHoogleは、関数の汎用タイプのおかげで、私が予想していたよりもはるかに悪い結果をもたらします。

なんでこんなに難しいの?

あなたが持っているので、もうそうではないことを願っていますfromIntegral

于 2011-08-09T21:15:20.970 に答える