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

ben*_*bot 14 haskell

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

reverseNum :: (Num a) => a -> a
reverseNum 123 = 321
reverseNum x = 0
Run Code Online (Sandbox Code Playgroud)

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

所以我将第一行更改为此

reverseNum :: (Integral a) => a -> a
Run Code Online (Sandbox Code Playgroud)

它起作用了.这很奇怪,因为我认为你是Num类型类的一部分,你也需要成为Eq的一部分.

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

reverseNum :: (Floating a) => a -> a
reverseNum 1.0 = 0.1
Run Code Online (Sandbox Code Playgroud)

它给了我同样的错误.

我知道你可以通过做类似的事情来解决这个问题,reverseNum :: (Num a, Eq a) ...但我想知道为什么Integral是唯一一个可以推导出Eq的东西.这是为什么?

PS我对haskell真的很新......温柔:)

Die*_*Epp 30

简短的回答

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

class Num a where
    ...
Run Code Online (Sandbox Code Playgroud)

而定义Integral需要类型RealEnum:

class (Real a, Enum a) => Integral a where
    ...
Run Code Online (Sandbox Code Playgroud)

Real暗示两者NumOrd......

class (Num a, Ord a) => Real a where
    ...
Run Code Online (Sandbox Code Playgroud)

并且Ord,自然地暗示Eq:

class Eq a => Ord a where
    ...
Run Code Online (Sandbox Code Playgroud)

这一行意味着为了实现某些功能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.
Run Code Online (Sandbox Code Playgroud)

这里,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..]]
Run Code Online (Sandbox Code Playgroud)

因此有意义的是Num它不是子类Eq,因为有一些有用的类型可以实现Num但不能实现Eq.