Gilgamesz
Gilgamesz

Reputation: 5073

Avoiding do statement in foldM

g ll = 
  foldlM (\ some_list b -> do
    part <- f b
    return (some_list ++ part)) [] ll

In above piece of code I use do statement just because the f function return a monad type: M a where a is a list. ( I "unpack" that list with <-. This is why I need do statement). Can I avoid it and write that more concisely? ( Yes, I know that I can write it using >>= but I also consider something nicer.)

Upvotes: 1

Views: 140

Answers (2)

dfeuer
dfeuer

Reputation: 48611

foldlM is the wrong tool for the job. You can use it, as chepner's answer shows, but the way you're concatenating lists could get expensive. Luka Rahne's one-liner is much better:

g ll = fmap concat (mapM f ll)

Another option is to use foldr directly:

g = foldr (\x r -> (++) <$> f x <*> r) (pure [])

Another way to write the second version, by inlining the foldr:

g [] = pure []
g (x : xs) = (++) <$> f x <*> g xs

Upvotes: 6

chepner
chepner

Reputation: 531878

Your do expression

do
  part <- f b
  return (some_list ++ part)

follows the extract-apply-return pattern that fmap captures (due to the identity fmap f k = k >>= return . f

  1. You extract part from the computation f b
  2. You apply (some_list ++) to part
  3. You return the result of that application.

This can be done in one step with fmap:

-- foldlM (f b >>= return . (some_list ++)) [] ll
foldlM (\some_list b -> fmap (some_list ++) (f b)) [] ll

Upvotes: 1

Related Questions