{-# LANGUAGE InstanceSigs, KindSignatures #-} class Functor' (f :: * -> *) where fmap' :: (a -> b) -> f a -> f b class (Functor' m) => Monad' m where join' :: m (m a) -> m a return' :: a -> m a join'' :: (Monad' m) => m (m c) -> m c join'' x = bind' x (\ y -> y) -- bind' (c1 :: m (m c)) (f :: m c -> m c) :: m c -- we are instantiating a to m c and b to c in the type of bind' bind' :: (Monad' m) => m a -> (a -> m b) -> m b bind' c1 f = join' (fmap' f c1) -- fmap' f :: m a -> m (m b) -- fmap' f c1 :: m (m b) -- Kleisli composition kcomp :: (Monad' m) => (a -> m b) -> (b -> m c) -> (a -> m c) kcomp f g = \ x -> (f x) `bind'` g -- e :: a -- e' :: () -> a -- e = e' () -- e' = \ x -> e bind2 :: (Monad' m) => m a -> (a -> m b) -> m b bind2 x f = (kcomp (\ y -> x) f) () -- :: () -> m b class (Functor' m) => Monad'' m where bind'' :: m a -> (a -> m b) -> m b return'' :: a -> m a instance Functor' Maybe where fmap' :: (a -> b) -> Maybe a -> Maybe b fmap' f Nothing = Nothing fmap' f (Just x) = Just (f x) data Exp = Base Integer | Add Exp Exp | Mul Exp Exp | Div Exp Exp deriving (Show, Eq) eval :: Exp -> Integer eval (Base n) = n eval (Add e e') = eval e + eval e' eval (Mul e e') = eval e * eval e' eval (Div e e') = eval e `div` eval e' eval' :: Exp -> Maybe Integer eval' (Base n) = Just n eval' (Add e e') = case eval' e of Nothing -> Nothing Just r1 -> case eval' e' of Nothing -> Nothing Just r2 -> Just (r1 + r2) eval' (Mul e e') = case eval' e of Nothing -> Nothing Just r1 -> case eval' e' of Nothing -> Nothing Just r2 -> Just (r1 * r2) eval' (Div e e') = case eval' e of Nothing -> Nothing Just r1 -> case eval' e' of Nothing -> Nothing Just r2 -> if r2 == 0 then Nothing else Just (r1 `div` r2) instance Monad'' Maybe where bind'' :: Maybe a -> (a -> Maybe b) -> Maybe b bind'' Nothing f = Nothing bind'' (Just x) f = f x return'' :: a -> Maybe a return'' x = Just x eval'' :: Exp -> Maybe Integer eval'' (Base n) = return n eval'' (Add e e') = eval'' e >>= (\ x -> eval'' e' >>= (\ y -> return (x + y) ) ) eval'' (Mul e e') = eval'' e >>= (\ x -> eval'' e' >>= (\ y -> return (x * y) ) ) eval'' (Div e e') = eval'' e >>= (\ x -> eval'' e' >>= (\ y -> if y == 0 then Nothing else return (x `div` y) ) ) -- using Do-notation eval''' :: Exp -> Maybe Integer eval''' (Base n) = return n eval''' (Add e e') = do x <- eval''' e y <- eval''' e' return (x+y) eval''' (Mul e e') = do x <- eval''' e y <- eval''' e' return (x*y) eval''' (Div e e') = do x <- eval''' e y <- eval''' e' if y == 0 then Nothing else return (x `div` y) -- > -- eval''' (Add e e') = do -- eval''' e >>= \ x -> -- translate do y <- eval''' e' -- return (x+y) -- > -- eval''' (Add e e') = -- eval''' e >>= \ x -> -- eval''' e' >>= \ y -> -- return (x+y)