[Haskell-cafe] mdo with multiple values

Joachim Breitner mail at joachim-breitner.de
Wed Jan 15 09:57:57 UTC 2014

Dear List,

a little puzzle. 

Given a monad M with a MonadFix instance, and these two functions:
        act1 :: T -> M ()
        act2 :: a -> M T

I morally want to write this function:
        foo :: [a] -> M ()
        foo = mdo
          mapM_ act1 xs
          xs <- mapM act2
          return ()

Unfortunately, that will not work: mapM_ will force xs before any of it
can be generated. But morally it should be possible, as the lists passed
to mapM_ and mapM have the same, already known list.

So here is my solution (which is a bit more general, because I happen to
need some that in one place):

        mapFstMapSnd :: MonadFix m => [(a -> m (), m a)] -> m ()
        mapFstMapSnd xs = const () `liftM` go xs (return [])
            go [] cont = cont
            go ((f,s):xs) cont = mdo
                f v
                (v:vs) <- go xs $ do
                    vs <- cont
                    v <- s
                    return (v:vs)
                return vs

Using that, I can write
        foo = mapFstSnd . map (x -> (act1, act2 x))

Are there better solutions? Simpler ones? Or possibly ones that do not
require a partial pattern?

Hmm, and thinking while writing lets me come up with

        data FunSplit m where
            FunSplit :: forall m a . (a -> m ()) -> m a -> FunSplit m
        mapFstMapSnd :: forall m. MonadFix m => [FunSplit m] -> m ()
        mapFstMapSnd xs = const () `liftM` go xs (return ())
            go :: [FunSplit m] -> m b -> m b
            go [] cont = cont
            go (FunSplit f s:xs) cont = mdo
                f v
                (v,vs) <- go xs $ do
                    vs <- cont
                    v <- s
                    return (v,vs)
                return vs
        foo :: [SPut] -> SPut
        foo = mapFstMapSnd . map go
            where go x = FunSplit act1 (act2 x)
Any suggestions for improvement?


Joachim Breitner
  e-Mail: mail at joachim-breitner.de
  Homepage: http://www.joachim-breitner.de
  Jabber-ID: nomeata at joachim-breitner.de

-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 181 bytes
Desc: This is a digitally signed message part
URL: <http://www.haskell.org/pipermail/haskell-cafe/attachments/20140115/bebe2979/attachment.sig>

More information about the Haskell-Cafe mailing list