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

时间:2019-03-01 21:10:21

标签: 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)

因此writertell互相递归调用。但是我不明白那是怎么回事。是否有停止条件?这是因为Haskell的惰性吗?有人可以照亮它吗?

1 个答案:

答案 0 :(得分:11)

请注意MINIMAL annotation

{-# MINIMAL (writer | tell), listen, pass #-}

这告诉GHC需要使用哪些类方法来构成完整的实例。通常,这组方法是由编译器推断的-只是没有默认实现的方法集-但在某些情况下,明确指定它很有用。这种情况就是这样。

MINIMAL的{​​{1}}注释表示必须始终实现MonadWriterlisten,这是有道理的,因为这些方法没有任何默认实现。然后继续说一些更有趣的事情:pass writer必须实现,但不一定要同时实现。

这是可行的,因为如果实例提供了tell的实现,那么就提供的writer而言,将使用tell的默认实现来实现它。同样,如果实例提供writer但不提供tell,则反之亦然。 writer批注可保护实例避免提供都不的实现,因此,没有一个完整的实例可以同时使用这两个默认实现。