无法从(Num a)或(浮动a)推导出(Eq a)。但是可以从(积分a)中推导出(方程a)。为什么?

时间:2013-09-07 18:22:29

标签: haskell

我正在浏览一个haskell教程(非常好地了解一下haskell),我正在玩这本基于本书其中一个函数编写的代码。

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

和ghci告诉我,它不能从(Num a)推断出(Eq a)。

所以我将第一行改为

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

它有效。这很奇怪,因为我认为你是Num类型类的一部分,你也需要成为Eq的一部分。

我尝试了另外一件事来满足我的好奇心并将前两行更改为

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

它给了我同样的错误。

我知道您可以通过执行类似reverseNum :: (Num a, Eq a) ...的操作来解决此问题,但我想知道为什么Integral是唯一可以推导出Eq的方法。 那是为什么?

P.S。我对哈斯克尔真的很新......所以......温柔:)。

1 个答案:

答案 0 :(得分:30)

简短回答

因为这是前奏中Num的定义:

class Num a where
    ...

Integral的定义要求类型为RealEnum

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。或者我们可以说OrdEq的子类。总之...

摘要是Num不是Eq的子类,但IntegralEq的子类。

答案很长(为什么?)

您可以设想以无法实现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 }。