Haskell如何避免在布尔值定义中出现无限递归?

6
几年前我读到了关于Haskell如何比较布尔表达式的文章,我想看看是否可以在我的项目(F#)中使用相同的概念,但我不明白它是如何工作的。
来源:https://hackage.haskell.org/package/ghc-prim-0.10.0/docs/src/GHC.Classes.html#%3D%3D
x /= y               = not (x == y)
x == y               = not (x /= y) 

这是完全有道理的,但它为什么不会陷入无尽的递归呢?
在我的项目中,我有已花费和未花费的硬币,我认为它们可以像布尔值一样处理,其中一个硬币在未花费时表示它没有被花费,在已花费时表示它没有未花费。
3个回答

12
这些是Eq类型类的默认方法。这意味着,如果某个类型实例化了Eq但没有提供==的实现,它将被定义为not (x /= y)。如果它没有提供/=的实现,它将被定义为not (x == y)。如果它既没有提供==的实现,也没有提供/=的实现,那么将会出现无限递归。
请注意,在这两行之后有一个{-# MINIMAL (==) | (/=) #-}的注释。这意味着“Eq的最小实现将定义==/=”,并指示编译器在创建一个没有定义至少其中一个方法的实例时产生警告。

9

如果你像那样声明普通函数,它将无限循环。但在这种情况下,这些只是类方法的默认定义。这些中至少有一个应该由该类的每个特定实例进行重写(这就是 {-# MINIMAL (==) | (/=) #-} 的意思)。

这种情况成为 CLC 提案的主题:https://github.com/haskell/core-libraries-committee/issues/3。因此,将来可能通过从类中移除 (/=) 方法并将其作为单独的函数来解决此问题。


8
这是一个类型类,实例应该进行实现。你看到的是一个默认(回退)实现。
编译器通常会强制执行这一点。该类不仅提供函数签名和默认实现,而且展示:
class Eq a where
  -- …
  {-# <b>MINIMAL (==) | (/=)</b> #-}

最小化表示这个类型类的实例要么必须实现(==),要么实现(/=)(当然也可以两者都实现)。

对于任何有意义的Eq实例也是如此,例如Int

instance Eq Int where
    (==) = eqInt
    (/=) = neInt
在这种情况下,eqIntneInt的实现如下:
eqInt, neInt :: Int -> Int -> Bool
(I# x) `eqInt` (I# y) = isTrue# (x ==# y)
(I# x) `neInt` (I# y) = isTrue# (x /=# y)

然后,这些函数可以在未打包的Int#值上进行操作。

请注意,Haskell中的class是一个typeclass,它更像是面向对象编程中的interface。它不处理(具体)数据,只提供应该被实现的接口。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接