如何理解MonadWriter Typeclass中的递归函数调用

McB*_*den 0 haskell

mtl库中,我看到了以下定义MonadWriter:

class (Monoid w, Monad m) => MonadWriter w m | m -> w where
#if __GLASGOW_HASKELL__ >= 707
    {-# MINIMAL (writer | tell), listen, pass #-}
#endif
    -- | @'writer' (a,w)@ embeds a simple writer action.
    writer :: (a,w) -> m a
    writer ~(a, w) = do
      tell w
      return a

    -- | @'tell' w@ is an action that produces the output @w@.
    tell   :: w -> m ()
    tell w = writer ((),w)
Run Code Online (Sandbox Code Playgroud)

所以writertell递归地互相调用.但我无法理解它是如何工作的.有停止条件吗?这是否因为Haskell的懒惰而起作用?任何人都能发光吗?

Ale*_*ing 11

注意MINIMAL注释:

{-# MINIMAL (writer | tell), listen, pass #-}
Run Code Online (Sandbox Code Playgroud)

这告诉GHC需要实现哪些类方法来创建一个完整的实例.通常,这组方法是由编译器推断的 - 它只是没有默认实现的方法集 - 但在某些情况下,显式指定它是有用的.这就是这种情况.

MINIMAL用于注释MonadWriter说,listenpass必须始终实现,这是有道理的,因为这些方法没有任何的默认实现.它接着说更有趣的东西:要么writer 还是 tell必须执行,但不一定都.

这样就可以了,因为如果实例提供了一个实现writer,那么默认实现tell将用于根据提供的writer实现来实现它.同样,如果实例提供tell但不是,则反转将为真writer.该MINIMAL注释从供给的实现保护的情况下没有,所以没有完整的情况下都不能有同时使用的默认实现一次.