Haskell如何避免布尔值定义中的无休止递归?

s2j5cfk0  于 2023-10-19  发布在  其他
关注(0)|答案(3)|浏览(134)

几年前,我读到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)

这完全有道理,但它怎么不会以一个永无止境的递归结束呢?
背景:在我的项目中,我有花费和未花费的硬币,我认为它们可以类似于布尔值来处理,当一个硬币没有花费时,它是未花费的,当它没有花费时,它是花费的。

ego6inou

ego6inou1#

这些是Eq类型类的默认方法。这意味着,如果某个类型示例化了Eq,但没有提供==的实现,它将被定义为not (x /= y)。如果它不提供/=的实现,则将其定义为not (x == y)。如果它没有提供任何一个方法的实现,你将得到无限的递归。
还要注意这两行之后的{-# MINIMAL (==) | (/=) #-}注解。这意味着“Eq的最小实现将定义==/=“,并指示编译器在创建没有定义至少一个这些方法的示例时产生警告。

dfddblmv

dfddblmv2#

如果你像那样声明普通函数,它会无限循环。但在这种情况下,这些只是类方法的默认定义。该类的每个特定示例都应该至少覆盖其中一个({-# MINIMAL (==) | (/=) #-}就是这么说的)。
这种情况是《油污损害民事责任公约》一项提案的主题:https://github.com/haskell/core-libraries-committee/issues/3。所以将来这种情况可能会通过简单地从类中删除(/=)方法并使其成为一个单独的函数来解决。

9w11ddsr

9w11ddsr3#

这完全有道理,但它怎么不会以一个永无止境的递归结束呢?
这是一个类型类,示例应该做一个实现。你所看到的是一个默认的(回退)实现。
实际上,编译器通常会强制这样做。该类不仅提供函数签名和默认实现,还显示:

class Eq a where
  -- …
  {-# MINIMAL (==) | (/=) #-}

最小值意味着类型类的示例必须实现(==)(/=)(它们当然可以实现两者)。
对于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。它不处理(具体的)数据,它只是提供了一个应该实现的接口。

相关问题