Monadic transformation on a list, done in three ways I am working my way through the Haskell Book and ran into the exercises at the end of the Monad chapter(18). One in particular asked to define a function with the following signature:

meh :: Monad m =&gt; [a] -&gt; (a -&gt; m b) -&gt; m [b]


So I did. I found this routine difficult to implement at first, but once I understood what I was doing and what I needed to do a little better I figured it out.

I have three versions of the routine, my first attempt, a slightly refactored attempt, and a final attempt using do-notation. I was wondering if anyone can give advice on how I could potentially refactor this routine further, or how I can make my implementation better. I feel like I can make the routine far cleaner than I have it, but I am not sure how.

WARNING: If you are reading the Haskell Book and want to work through the exercises yourself, I recommend you do not read any further

Here are all three implementations

-- Attempt #1 with helper routine
meh :: Monad m =&gt; [a] -&gt; (a -&gt; m b) -&gt; m [b]
meh list fn = doWork list (return $ []) fn
  where 
    doWork (x:xs) base f
      | length xs == 0 = (addToMonad x base f) &gt;&gt;= (\x -&gt; return $ reverse x)
      | otherwise = doWork xs (addToMonad x base f) f

addToMonad x baseMonad fn = do
  someVal &lt;- (fn x)
  base &lt;- baseMonad
  return $ someVal:base

-- Attempt #2 with a fold
meh' :: Monad m =&gt; [a] -&gt; (a -&gt; m b) -&gt; m [b]
meh' list fn = (foldl (\acc x -&gt; (fn x) &gt;&gt;= (\y -&gt; acc &gt;&gt;= (\z -&gt; return $ y:z))) (return $ []) list) &gt;&gt;= (\x -&gt; return $ reverse x)

-- Attempt #3 with a fold and do-notation
mehDo :: Monad m =&gt; [a] -&gt; (a -&gt; m b) -&gt; m [b]
mehDo list fn = do 
  final &lt;- (foldl (\acc x -&gt; do
    val &lt;- (fn x) 
    mList &lt;- acc
    return $ val:mList)
    (return $ []) list)
  return $ reverse final


I want to say my last implementation is the easiest to read (it would be easier with better names, IMO) but I don't really know that it is. I am not super experienced in the ways of Haskell, so to be frank I read the routines really slowly regardless.

Anyway, advice or tips on how to make this cleaner would be much appreciated.
I'd say that the idiomatic way to write this function in Haskell is by composing a more primitive one with a map. Indeed, given the type signature of meh, it is very tempting to "prepare" a list of all the m b actions and then combine them in order:

meh :: Monad m =&gt; [a] -&gt; (a -&gt; m b) -&gt; m [b]
meh xs f = combine (f &lt;$&gt; xs)


Now, combine has type [m b] -&gt; m [b]. To process that list, we can use a fold. You have used foldl in your examples but you ended up reversing the list which is a clear sign that you may have wanted a foldr instead. And we can indeed do that:

combine :: Monad m =&gt; [m b] -&gt; m [b]
combine = foldr (\ x xs -&gt; (:) &lt;$&gt; x &lt;*&gt; xs) (return [])


Here the functor (&lt;$&gt;) and applicative (&lt;*&gt;) combinators allow to write something that looks a bit direct style (we are basically using (:) to construct a list by giving its head and tail) but that takes care of the monadic actions.