-- Monad example using parents of sheep. Original by: {- Author: Jeff Newbern Maintainer: Jeff Newbern Time-stamp: License: GPL -} -- Modified by Scot Drysdale on 2/29/08 import Monad -- to get mplus -- everything you need to know about sheep data Sheep = Sheep {name::String, mother::Maybe Sheep, father::Maybe Sheep} -- we show sheep by name instance Show Sheep where show s = show (name s) -- comb is a combinator for sequencing operations that return Maybe comb :: Maybe a -> (a -> Maybe b) -> Maybe b comb Nothing _ = Nothing comb (Just x) f = f x -- now we can use `comb` to build complicated sequences maternalGrandfatherC :: Sheep -> Maybe Sheep maternalGrandfatherC s = (Just s) `comb` mother `comb` father fathersMaternalGrandmotherC :: Sheep -> Maybe Sheep fathersMaternalGrandmotherC s = (Just s) `comb` father `comb` mother `comb` mother mothersPaternalGrandfatherC :: Sheep -> Maybe Sheep mothersPaternalGrandfatherC s = (Just s) `comb` mother `comb` father `comb` father -- Our sheep family tree adam = Sheep "Adam" Nothing Nothing eve = Sheep "Eve" Nothing Nothing uranus = Sheep "Uranus" Nothing Nothing gaea = Sheep "Gaea" Nothing Nothing kronos = Sheep "Kronos" (Just gaea) (Just uranus) holly = Sheep "Holly" (Just eve) (Just adam) roger = Sheep "Roger" (Just eve) (Just kronos) molly = Sheep "Molly" (Just holly) (Just roger) dolly = Sheep "Dolly" (Just molly) Nothing -- print Dolly's maternal grandfather main1 = do print (maternalGrandfatherC dolly) print (fathersMaternalGrandmotherC dolly) print (mothersPaternalGrandfatherC dolly) ---- Use monads instead of `comb` -- the Maybe type is already declared as an instance of the Monad class -- in the standard prelude, so we don't actually need to define it here. -- just remember that it looks something like this: -- instance Monad Maybe where -- Nothing >>= f = Nothing -- (Just x) >>= f = f x -- return = Just -- fail s = Nothing -- now we can use monad operations to build complicated sequences -- Note that "return" has nothing to do with ending the function call! maternalGrandfatherM :: Sheep -> Maybe Sheep maternalGrandfatherM s = return s >>= mother >>= father fathersMaternalGrandmotherM :: Sheep -> Maybe Sheep fathersMaternalGrandmotherM s = return s >>= father >>= mother >>= mother mothersPaternalGrandfatherM :: Sheep -> Maybe Sheep mothersPaternalGrandfatherM s = return s >>= mother >>= father >>= father main2 = do print (maternalGrandfatherM dolly) print (fathersMaternalGrandmotherM dolly) print (mothersPaternalGrandfatherM dolly) -- we can also use do-notation to build complicated sequences maternalGrandfather :: Sheep -> Maybe Sheep maternalGrandfather s = do m <- mother s father m fathersMaternalGrandmother :: Sheep -> Maybe Sheep fathersMaternalGrandmother s = do f <- father s gm <- mother f mother gm mothersPaternalGrandfather :: Sheep -> Maybe Sheep mothersPaternalGrandfather s = do m <- mother s gf <- father m father gf main3 = do print (maternalGrandfather dolly) print (fathersMaternalGrandmother dolly) print (mothersPaternalGrandfather dolly) -- Also demonstrate MonadPlus, define in Monad as: --class (Monad m) => MonadPlus m where -- mzero :: m a -- mplus :: m a -> m a -> m a --instance MonadPlus Maybe where -- mzero = Nothing -- Nothing `mplus` x = x -- x `mplus` _ = x -- Can be used to create parent function and grandparent functions: -- returns a parent, if one exists parent :: Sheep -> Maybe Sheep parent s = (mother s) `mplus` (father s) -- returns a grandparent, if one exists. -- Why does "return s >>= parent >>= parent" sometimes fail? grandparent :: Sheep -> Maybe Sheep grandparent s = (mother s >>= parent) `mplus` (father s >>= parent)