15

私は haskell チュートリアル (Learn you a haskell for great good) を行っていて、本の関数の 1 つに基づいて書いたこのコードをいじっていました。

reverseNum :: (Num a) => a -> a
reverseNum 123 = 321
reverseNum x = 0

ghci は、(Num a) から (Eq a) を推測できないことを教えてくれます。

だから私はこれに最初の行を変更します

reverseNum :: (Integral a) => a -> a

そしてそれはうまくいきました。これは奇妙でした。なぜなら、私は、Eq. の一部である必要がある Num 型クラスの一部であると考えていたからです。

好奇心を満たすためにもう1つ試してみて、最初の2行をこれに変更しました

reverseNum :: (Floating a) => a -> a
reverseNum 1.0 = 0.1

それは私に同じエラーを与えました。

次のようなことを行うことでこれを修正できることは知っていますがreverseNum :: (Num a, Eq a) ...、Eq を推定できるのは Integral だけである理由を知りたいです。何故ですか?

PS私はhaskellに本当に慣れていないので...優しくしてください:)

4

1 に答える 1

30

簡潔な答え

Numそれがプレリュードの定義だからです:

class Num a where
    ...

の定義でIntegralは、タイプがRealand である必要がありEnumます。

class (Real a, Enum a) => Integral a where
    ...

そして両方をReal意味します...NumOrd

class (Num a, Ord a) => Real a where
    ...

そしてOrd、当然のことながら、次のことを意味しEqます。

class Eq a => Ord a where
    ...

この行は、何かを実装するためにはOrd、それも実装する必要Eqがあることを意味します。Ordまたは、 のサブクラスであると言えEqます。ともかく...

要約すると、は のサブクラスでNumはなく、のサブクラスです。EqIntegralEq

長い答え(なぜ?)

Num実装を不可能にする方法で実装することは想像できますEq

newtype Sequence = Sequence (Integer -> Integer)

instance Num Sequence where
  (Sequence x) + (Sequence y) = Sequence $ \pt -> x pt + y pt
  (Sequence x) - (Sequence y) = Sequence $ \pt -> x pt - y pt
  (Sequence x) * (Sequence y) = Sequence $ \pt -> x pt * y pt
  negate (Sequence x) = Sequence $ \pt -> -pt
  abs (Sequence x) = Sequence $ \pt -> abs pt
  signum (Sequence x) = Sequence $ \pt -> signum pt
  fromInteger = Sequence . const

-- Ignore the fact that you'd implement these methods using Applicative.

ここで、Sequenceは計算可能なすべてのシーケンスを表す型です。Eqシーケンスが無限に長いため、合理的な方法で実装することはできません!

instance Eq Sequence where
  -- This will never return True, ever.
  (Sequence x) == (Sequence y) =
      and [x pt == y pt | pt <- [0..]] &&
      and [x pt == y pt | pt <- [-1,-2..]]

Numしたがって、が のサブクラスではないことは理にかなっています。Eqなぜなら、を実装できるが を実装できない便利な型があるからです。NumEq

于 2013-09-07T18:40:24.620 に答える