typeclass bimap怎么没有循环定义

qwe*_*938 3 haskell

我在理解这段代码时缺少什么关键的直觉?我不明白这些是如何组成的。首先需要一个函数(a->c)和构造类型(fab)。然而,第二次产量(时尚)。此外,第一和第二是根据看起来循环的双图来定义的。

class Bifunctor f where
  bimap :: (a -> c) -> (b -> d) -> f a b -> f c d
  bimap g h = first g . second h
  first :: (a -> c) -> f a b -> f c b
  first g = bimap g id
  second :: (b -> d) -> f a b -> f a d
  second = bimap id
Run Code Online (Sandbox Code Playgroud)

Sil*_*olo 5

second咖喱化了。你可以写出隐含参数,它将与 对称first

first g = bimap g id
second g = bimap id g
Run Code Online (Sandbox Code Playgroud)

至于你问的定义是否循环的问题,答案是肯定的。它们是圆形的。根据严格阅读Haskell标准,以下实现是正确的

data F a b = F a b

instance Bifunctor F -- No functions implemented; take all three defaults
Run Code Online (Sandbox Code Playgroud)

这将根据 Haskell 标准进行编译。但任何呼叫firstsecond、 或的尝试bimap都会触底,因为他们只会永远互相呼叫。

但是,如果您查看 的源代码Bifunctor,就会发现还有另一个小注释。

{-# MINIMAL bimap | first, second #-}
Run Code Online (Sandbox Code Playgroud)

这不是一个普通的评论。这是针对 GHC(最流行的 Haskell 编译器)的特殊指令。GHC 特别支持最小指令。这声明 的实例仅在至少Bifunctor实现或同时实现和 时才是完整的。因此,在 GHC 上,如果您自己的 未能满足该条件,您将收到编译器错误。这也反映在Hackage 文档中 bimapfirstsecondinstance

最小完整定义

bimap | first, second
Run Code Online (Sandbox Code Playgroud)

我们期望,作为程序员,您可以覆盖其中一些默认值,而其余的默认值可以默默地就位。

您可以在内置类型类中更直接地看到相同的行为Eq

class  Eq a  where
    (==), (/=)           :: a -> a -> Bool

    {-# INLINE (/=) #-}
    {-# INLINE (==) #-}
    x /= y               = not (x == y)
    x == y               = not (x /= y)
    {-# MINIMAL (==) | (/=) #-}
Run Code Online (Sandbox Code Playgroud)

(==)都是(/=)相互实现的,并且MINIMAL底部有一个指令指示任何实例必须至少实现这两个函数之一。