Page 1

Page 2
• The first version of eval again:
• ```eval :: Expr -> Integer
eval (Num n)     = n
eval (Add e1 e2) = eval e1 + eval e2
eval (Mul e1 e2) = eval e1 * eval e2```
• We can rewrite it using functions from the
`Applicative`
class
• ```evalA (Num n)   = pure n
evalA (Add a b) = (+) <\$> evalA a <*> evalA b
evalA (Mul a b) = (*) <\$> evalA a <*> evalA b```
• What is the type
`evalA`
?
Page 3
• `evalA :: Applicative f => Expr -> f Integer`
• It works for any type in the
`Applicative`
class!
• It also works for any type in the
`Monad`
class (since it is a subclass).
• Example:
`Maybe`
is in the
`Applicative`
class, so we can get
• `evalA :: Expr -> Maybe Integer`
Page 4

# Avoiding division by zero

• ```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
`<*>`
or
`=<<`
, so I used the
`do`
notation.
Page 5

# Looking up variables

• Any function type
`(e->)`
is in
`Applicative`
, so we can pass extra arguments.
• We can make the environment implicit.
• ```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)
```
Page 6

# Combining effects?

• We made two separate extensions of
`evalA`
:
• ```evalD :: Expr -> Maybe Integer
evalE :: Expr -> [(Name, Integer)] -> Integer```
• Can we combine them into this?
• `evalM :: Expr -> [(Name, Integer)] -> Maybe Integer`
• Or, if we give our monad a name:
• ```type Eval a = [(Name, Integer)] -> Maybe a

evalM :: Expr -> Eval Integer```
• But is
`Eval`
an instance of
`Monad`
?
• Unfortunately not!
Page 7

• We need to define a new type if we want to combine effects (or look for types in the libraries)
• ```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

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)
```
Page 8

# Combining effects

```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)
```
Page 9

# Final thoughts on the monadic evaluator

• In examples small enough to fit on a slide, using monads like this is probably overkill.
• The benefits show up when the code gets larger and you can add more effects to the monad without rewriting all of the code that uses it.
• By using
`Either`
`Maybe`
`Nothing`
`evalM`