suggestions for improving MonadWriter

Iavor Diatchki iavor.diatchki at
Mon Jan 28 07:18:06 CET 2013

Hi Petr,

you might also consider using `monadLib`, it is an alternative to MTL that
I and some of my colleagues have used for a few years now.  It does both of
the things that you suggest (i.e., the `Monoid` constraints are on the
instances, not the class, and it provides a method to gather collected
output, in `monadLib` this operation is called `collect`).  Generally
`monadLib` provides similar functionality to MTL but with a number of
improvements like the ones you suggest (e.g., same functionality with fewer
types, improved support for working with continuations, a correct
implementation of backtracking, etc.)

Happy hacking,

On Sun, Jan 27, 2013 at 12:30 PM, Petr P <petr.mvd at> wrote:

>   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
> against.
> (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
> _______________________________________________
> Libraries mailing list
> Libraries at
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <>

More information about the Libraries mailing list