suggestions for improving MonadWriter

Petr P petr.mvd at
Sun Jan 27 21:30:31 CET 2013

  Dear maintainers,

I have two suggestions for MonadWriter:

(1) Remove the "Monoid w" constraint from the definition.

The constraints prevent creating new instances of the class that have only
an implied monoid. For example, I needed to create a simple writer which
always stores the last written element. I had to wrap it into Last, which
was a nuisance for users of my library. Without the constraint, my instance
would be quite simpler and still satisfying all the laws. There are many
other similar use cases, like counting the number of written values (and
disregarding their actual content) etc.

The constraint is meant to ensure that instances of that class obey the
monad laws. But it's not the responsibility of a type class that its
instances satisfy the laws. They could violate them even without this
constraints. Instead, this constraint should be specified (and it is) in
the definition of their instances.

It has been discussed in haskell-cafe <
haskell-cafe/2012-December/thread.html#105088> with arguments for and

(2) Add

  -- | @contained m@ executes the action @m@ in a contained environment and
  -- returns its value and its output. The current output is not modified.
  contained :: m a -> m (a, w)

to MonadWriter.

This generalizes "pass" and "listen"  and has it's a sort of inverse to
"writer" with these simple laws:

  writer <=< contained   = id
  contained . writer     = return

It seems as a understandable set of laws that its instances should obey.

It also expresses the same concept as "runWriterT" does, but inside the
type class. In particular, for "WriterT" we have

  contained :: (Monoid w, Monad m) => WriterT w m a -> WriterT w m (a, w)
  contained = lift . runWriterT

Current instances won't be affected as "contained" can be expressed using
"pass" and "listen" (and vice versa).
Full details available at
[There "contained" is expressed without the "Monoid w" constraint as
suggested in (1). If we keep the constraint, "contained" can be expressed
more simply as
  containde k = pass (listen k >>= \x -> return (x, const mempty)).

Also, "contained" isn't probably a good name, I just couldn't think of
anything better.]

   Best regards,
   Petr Pudlak
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the Libraries mailing list