[Haskell-beginners] How Best to Deal with Nested Monads?

Brent Yorgey byorgey at seas.upenn.edu
Thu Sep 15 02:18:50 CEST 2011


On Wed, Sep 14, 2011 at 06:48:29PM -0400, Michael Craig wrote:
> Say we've got these types
> 
> lst :: m [a]
> getMB :: a -> m (Maybe b)
> getC :: b -> m c
> 
> and we want to map getMB and getC over the elements of lst, all the while
> discarding elements x where getMB x == Nothing.
> 
> (This could be generalized more by replacing Maybe with some monad m', but
> let's run with Maybe because it's easy to talk about.)
> 
> The best I've got (after some help on IRC) is this not-so-easy-to-read
> oneliner:
> 
> lst >>= (\x -> mapM (liftM (liftM getC) (getMB x)) >>= sequence
> . catMaybes

How about this:

  lst >>= (mapM getMB >=> (return . catMaybes) >=> mapM getC)

Everyone always forgets about (>=>).

> This is hard to read, but it's also bad because we run sequence twice (once
> inside of mapM). If we want to do multiple things to each element of lst, it
> would be nice to process each element completely before moving on to the
> next.

I wouldn't worry about running sequence twice.  Processing things by
chaining whole-structure transformations is the Haskell Way (tm).  All
that business about "doing only one traversal" is for people
programming in strict languages to worry about. The compiler can often
turn a chain of wholesale transformations into a single traversal
anyway.  In short, I see no particular reason why it is "nice" to
process each element completely before moving on.  Isn't it nicer to
be able to think in a more modular style?

-Brent



More information about the Beginners mailing list