eval :: Expr -> Integer eval (Num n) = n eval (Add e1 e2) = eval e1 + eval e2 eval (Mul e1 e2) = eval e1 * eval e2
Applicative
evalA (Num n) = pure n evalA (Add a b) = (+) <$> evalA a <*> evalA b evalA (Mul a b) = (*) <$> evalA a <*> evalA b
evalA
evalA :: Applicative f => Expr -> f Integer
Applicative
Monad
Maybe
Applicative
evalA :: Expr -> Maybe Integer
data Expr = -- ... Num, Add, and Mul as before ... Div Expr Expr evalD :: Expr -> Maybe Integer evalD (Num n) = pure n evalD (Add a b) = pure (+) <*> evalD a <*> evalD b evalD (Mul a b) = pure (+) <*> evalD a <*> evalD b evalD (Div a b) = do x <- evalD a y <- evalD b safeDiv x y safeDiv :: Integer -> Integer -> Maybe Integer safeDiv x 0 = Nothing safeDiv x y = Just (x `div` y)
safeDiv
doesn't quite fit with <*>
=<<
do
(e->)
Applicative
type Env = [(Name,Integer)]
evalE :: Expr -> Env -> Integer
evalE (Num n) = pure n
evalE (Var x) = varE x
evalE (Add a b) = pure (+) <*> evalE a <*> evalE b
evalE (Mul a b) = pure (*) <*> evalE a <*> evalE b
varE :: Name -> Env -> Integer
varE x env = case lookup x env of
Just n -> n
Nothing -> error ("Undefined variable: "++x)
evalA
evalD :: Expr -> Maybe Integer evalE :: Expr -> [(Name, Integer)] -> Integer
evalM :: Expr -> [(Name, Integer)] -> Maybe Integer
type Eval a = [(Name, Integer)] -> Maybe a evalM :: Expr -> Eval Integer
Eval
Monad
data Eval a = E ([(Name,Integer)] -> Maybe a) runE (E f) = f instance Functor Eval where fmap = liftM instance Applicative Eval where pure = return (<*>) = ap instance Monad Eval where return x = E (\ _ ->return x) E m >>= f = E (\env -> do a <- m env; runE (f a) env) divByZero = E (\ _ -> Nothing) lookupVar x = E (lookup x)
evalM :: Expr -> Eval Integer
evalM (Num n) = pure n
evalM (Var x) = lookupVar x
evalM (Add a b) = (+) <$> evalM a <*> evalM b
evalM (Mul a b) = (*) <$> evalM a <*> evalM b
evalM (Div a b) = do x <- evalM a
y <- evalM b
safeDiv x y
safeDiv x 0 = divByZero
safeDiv x y = pure (x `div` y)
Either
Maybe
Nothing
evalM