Yes, this is a use case for monad transformers. Given a computation of type:
computation :: (Monad m) => m (Maybe a)
... you can wrap it in MaybeT
using the MaybeT
constructor of the same name:
MaybeT :: (Monad m) => m (Maybe a) -> MaybeT m a
MaybeT computation :: (Monad m) => MaybeT m a
Then you can just write:
foo :: MaybeT Identity a
foo = do
stuff <- MaybeT getStuffSometimes
lift $ getStuffAlways stuff
... and MaybeT
will take care of all the Nothing
checks for you, making sure to thread them through your other monad.
When your done, just use runMaybeT
to unwrap the result, giving back an action in the base monad that returns a Maybe
:
runMaybeT :: (Monad m) => MaybeT m a -> m (Maybe a)
For example:
runMaybeT foo :: Identity (Maybe a)
Edit: To answer your follow up question, you would just do:
foo a = do
firstPart <- getStuffAlways
secondPart <- runMaybeT $ do
stuff <- MaybeT getStuffSometimes a
lift $ getStuffAlways stuff
return (firstPart, secondPart)