McBear Holden
McBear Holden

Reputation: 833

How to understand the recursive function call in MonadWriter Typeclass

In the mtl library, I see the definition of 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)

So writer and tell recursively calls each other. But I can't understand how that works. Is there a stop condition? Does this work because of the laziness of Haskell? Could anyone shine a light on it?

Upvotes: 0

Views: 61

Answers (1)

Alexis King
Alexis King

Reputation: 43872

Note the MINIMAL annotation:

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

This tells GHC which class methods need to be implemented to make a complete instance. Normally, this set of methods is inferred by the compiler—it’s just the set of methods that don’t have default implementations—but in some situations, it’s useful to specify it explicitly. This is one such situation.

The MINIMAL annotation for MonadWriter says that listen and pass must always be implemented, and this makes sense, since those methods don’t have any default implementations. It then goes on to say something more interesting: either writer or tell must be implemented, but not necessarily both.

This works out, since if an instance supplies an implementation of writer, then the default implementation for tell will be used to implement it in terms of the provided writer implementation. Likewise, the inverse will be true if an instance supplies tell but not writer. The MINIMAL annotation protects an instance from supplying an implementation of neither, so no complete instance can ever have both default implementations in use at once.

Upvotes: 11

Related Questions