Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

More idiomatic way of exiting mapM early

Tags:

haskell

monads

Given a list of actions that returns m (Maybe a) I'm trying to return m (Maybe [a]) where if any of the individual results are Nothing the whole result is Nothing. m contains StateT and I want to avoid running any actions after the first Nothing is returned.

Trying to use mapM and then moving the Maybe outside the list results in all the actions being run.

I have this solution but nested case statements with just a lot of wrapping and unwrapping gives me the feeling that there's probably a more elegant way of doing this. Usually when I have this feeling there a one-liner with a more general type that does exactly the same thing.

Any suggestions?

myMapM' :: Monad m => (t1 -> m (Maybe t)) -> [t1] -> m (Maybe [t])
myMapM' f [] = return (Just [])
myMapM' f (a:as) = do
  r <- f a 
  case r of
    Nothing -> return Nothing
    Just g -> do
      rs <- myMapM' f as
      case rs of
        Nothing -> return Nothing
        Just gs -> return (Just (g:gs))
like image 972
Brian Magnuson Avatar asked Feb 05 '23 09:02

Brian Magnuson


1 Answers

The behavior you want is that of the monad transformer MaybeT.

myMapM :: Monad m => (t1 -> m (Maybe t)) -> [t1] -> m (Maybe [t])
myMapM f = runMaybeT . mapM (MaybeT . f) 
like image 98
Li-yao Xia Avatar answered Feb 06 '23 22:02

Li-yao Xia