Solution to Exercise 4

Writing code which can be used in multiple monads requires careful thought about the definitions of each of the monads in which the computation is to be performed. The functions must be implemented using the subset of features common to all of the required monads.

A useful function in this instance is one to convert a value in the Maybe monad into any instance of the MonadPlus class:

Code available in exercise4.hs
-- convert a Maybe value into another monad
maybeToMonad :: (MonadPlus m) => Maybe a -> m a
maybeToMonad Nothing  = mzero
maybeToMonad (Just s) = return s

Note that this function acts like id when used in the Maybe monad. Using this function, we can define a version of parent similar to the definition we used in the List monad:

Code available in exercise4.hs
parent :: (MonadPlus m) => Sheep -> m Sheep
parent s = (maybeToMonad (mother s)) `mplus` (maybeToMonad (father s))

Because of the non-backtracking limitation of the Maybe monad, our definition of the grandparent function follows the definition we used with the Maybe monad, but with the addition of the calls to maybeToMonad necessary for use in the List monad:

Code available in exercise4.hs
grandparent :: (MonadPlus m) => Sheep -> m Sheep
grandparent s = (maybeToMonad (mother s) >>= parent) `mplus`
                (maybeToMonad (father s) >>= parent)

Return to exercises.