Не удалось вывести (Eq a) из (Num a) или из (Floating a). Но можно вывести (уравнение а) из (интеграла а). Почему?

Я просматриваю учебник по хаскелю (Узнайте хаскел во благо), и я играл с этим кодом, который я написал на основе одной из функций в книге.

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

и ghci говорит мне, что он не может вывести (Eq a) из (Num a).

Поэтому я меняю первую строку на это

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

и это сработало. Это было странно, потому что я думал, что, будучи частью класса типов Num, вы также должны быть частью Eq.

Я попробовал еще одну вещь, чтобы удовлетворить свое любопытство, и изменил первые 2 строки на это

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

и это дало мне ту же ошибку.

Я знаю, что вы можете исправить это, выполнив что-то вроде reverseNum :: (Num a, Eq a) ..., но я хочу знать, почему Integral является единственным, где можно вывести Eq. Почему это?

P.S. Я действительно новичок в haskell, так что... будьте нежны :)


person benbot    schedule 07.09.2013    source источник


Ответы (1)


Краткий ответ

Потому что это определение Num в прелюдии:

class Num a where
    ...

В то время как определение для Integral требует, чтобы тип был Real и Enum:

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

И Real подразумевает и Num, и Ord...

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

И Ord, естественно, подразумевает Eq:

class Eq a => Ord a where
    ...

Эта строка означает, что для того, чтобы что-то реализовало Ord, оно должно также реализовать Eq. Или мы могли бы сказать, что Ord является подклассом Eq. В любом случае...

Резюме состоит в том, что Num не является подклассом Eq, а Integral является подклассом Eq.

Длинный ответ (почему?)

Вы можете представить себе реализацию 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, потому что существуют полезные типы, которые могут реализовать Num, но не Eq.

person Dietrich Epp    schedule 07.09.2013
comment
Опередите меня в ответе, и ваш был намного лучше сформулирован. Проголосуйте. - person bheklilr; 07.09.2013
comment
Важно добавить, что это не определение Num в Haskell 2010 Prelude; это как раз то, что делает GHC. В Haskell 2010 Num a подразумевает как Eq a, так и Show a. - person Antal Spector-Zabusky; 08.09.2013
comment
Подождите... тогда почему у Int нет Eq? Разве int не является подтипом Integral? - person benbot; 08.09.2013
comment
@thecodethinker: Int — это тип, реализующий Eq, который является классом. Итак, у Int действительно есть Eq. - person Dietrich Epp; 08.09.2013
comment
Ладно... Думаю, я просто где-то ошибся. Спасибо - person benbot; 08.09.2013