[Haskell-cafe] mapM_ -> Monoid.Monad.map

Dan Doel dan.doel at gmail.com
Sat Jan 24 11:58:09 EST 2009

On Friday 23 January 2009 4:39:02 pm George Pollard wrote:
> > with your proposed mapM_ will leave a thunk equivalent to
> >
> > > () `mappend` () `mappend` () `mappend`...
> >
> > in memory until the mapM_ has completely finished, where each () is
> > actually an unevalutated thunk that still has a reference to one of the
> > elements in the lotsOfLargeStrings list.
> Perhaps this is why the Monoid instance for () in GHC's source has the
> comment "should this be strict?" :)

Aside from all the stuff about bottoms, a strict mappend will not solve the 
thunk problem above. The difference will be that with a strict mappend, once 
the delayed computation is demanded, with a strict mappend, evaluation will 
have to go all the way to the innermost application, possibly causing a stack 
overflow, whereas the lazy mappend (presumably \_ _ -> ()) will return () 
immediately, just throwing away most of the thunk. Whether or not such a thunk 
is actually built up in memory has to do with how mapM_ is written, not how 
mappend is written.*

-- Dan

[*] That's not 100% true. If we define:

  mapM_ f = loop mempty
   where loop acc (x:xs) = f x >>= \y -> loop (acc `mappend` y) xs
         loop acc [    ] = return acc

Then specialization to () could lead to strictness analysis reducing acc at 
each step. However, this definition is bad for lists, for example, since it 
results in:

  (((l1 ++ l2) ++ l3) ++ l4) ++ l5

style appending. And it may be a long shot to hope that GHC's optimizer 
produces the behavior we want in the () case. (And it still depends on mapM_ 
being written in one out of several available choices for the given type and 
expected results.)

More information about the Haskell-Cafe mailing list