data Expr = Num Integer | Add Expr Expr | Mul Expr Expr
eval :: Expr -> Integer eval (Num n) = n eval (Add a b) = eval a + eval b eval (Mul a b) = eval a * eval b
data Expr = Num Integer
| Var Name -- new
| Add Expr Expr
| Mul Expr Expr
type Name = String
vars :: Expr -> [Name] vars (Num n) = [] vars (Var x) = [x] vars (Add a b) = vars a `union` vars b vars (Mul a b) = vars a `union` vars b
union
Data.List
) instead of
++
eval :: [(Name,Integer)] -> Expr -> Integer eval env (Num n) = n eval env (Var x) = fromJust (lookup x env) eval env (Add a b) = eval env a + eval env b eval env (Mul a b) = eval env a * eval env b
lookup :: Eq key => [(key,value)] -> key -> Maybe value fromJust :: Maybe a -> a
fromJust
data Maybe a = Nothing | Just a
lookup
lookup :: Eq key => [(key,value)] -> key -> Maybe value lookup k [] = Nothing lookup k ((k',v):kvs) | k' == k = Just v | otherwise = lookup k kvs
diff :: Expr -> Name -> Expr
diff :: Expr -> Name -> Expr diff (Num n) x = Num 0 diff (Var y) x = if y==x then Num 1 else Num 0 diff (Add a b) x = Add (diff a x) (diff b x) diff (Mul a b) x = Add (Mul a (diff b x)) (Mul (diff a x) b)
diff ((Mul 2) (Var "x")) "x"
2*1+0*x
0+e
e+0
0*e
e*0
1*e
e*1
add
mul
Add
Mul
add (Num 0) b = b add a (Num 0) = a add a b = Add a b
mul (Num 0) b = Num 0 mul a (Num 0) = Num 0 mul (Num 1) b = b mul a (Num 1) = a mul a b = Mul a b
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) = pure (+) <*> evalA a <*> evalA b evalA (Mul a b) = pure (*) <*> 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
evalE :: Expr -> [(Name, Integer)] -> Integer evalE (Num n) = pure n evalE (Var x) = fromJust . lookup x evalE (Add a b) = pure (+) <*> evalE a <*> evalE b evalE (Mul a b) = pure (*) <*> evalE a <*> evalE b
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