几年前,我读到 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)
Run Code Online (Sandbox Code Playgroud)
这是完全有道理的,但是它怎么不会以永无休止的递归结束呢?
背景:在我的项目中,我已经花费和未花费的硬币,我认为它们可以像布尔值一样处理,当硬币没有花费时,它是未花费的,当它没有未花费时,它是花费的。
sep*_*p2k 12
这些是类型类的默认方法Eq
。这意味着如果某种类型实例化Eq
并且不提供 的实现==
,它将被定义为not (x /= y)
。如果它没有提供 的实现/=
,它将被定义为not (x == y)
。如果它不提供任一方法的实现,您确实会得到无限递归。
另请注意{-# MINIMAL (==) | (/=) #-}
这两行后面的注释。Eq
这意味着“将定义==
或”的最小实现/=
,并指示编译器在您创建未定义至少其中一个方法的实例时生成警告。
如果您像这样声明普通函数,它将无限循环。但在本例中,这些只是类方法的默认定义。至少其中一个应该被此类的每个特定实例覆盖(这就是所说的{-# MINIMAL (==) | (/=) #-}
)。
这种情况是 CLC 提案的主题:https://github.com/haskell/core-libraries-committee/issues/3。因此,将来这种情况可能会通过简单地(/=)
从类中删除该方法并使其成为一个单独的函数来解决。
这是完全有道理的,但是它怎么不会以永无休止的递归结束呢?
这是一个类型类,实例应该进行实现。您看到的是默认(后备)实现。
事实上,编译器通常会强制执行这一点。该类不仅提供函数签名和默认实现,还显示:
class Eq a where
-- …
{-# MINIMAL (==) | (/=) #-}
Run Code Online (Sandbox Code Playgroud)
最小意味着类型类的实例必须实现(==)
或(/=)
(当然可以两者都实现)。
事实上,对于 的任何有意义的实例也是如此Eq
,例如Int
:
Run Code Online (Sandbox Code Playgroud)instance Eq Int where (==) = eqInt (/=) = neInt
其中eqInt
和neInt
在本例中实现为:
Run Code Online (Sandbox Code Playgroud)eqInt, neInt :: Int -> Int -> Bool (I# x) `eqInt` (I# y) = isTrue# (x ==# y) (I# x) `neInt` (I# y) = isTrue# (x /=# y)
然后,它们具有==#
可处理未装箱 Int#
值的函数。
请注意, Haskell 中的类是类型类,这看起来更像是面向对象编程中的接口。它不处理(具体)数据,它只是提供一个应该实现的接口。