- This was originally planned to be part of the lecture on Recursive Data Types.

**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`

dataExpr=NumInteger|VarName-- new|AddExprExpr|MulExprExprtypeName=String

- Example: compute the list of variable names that occur in an expression
`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`

- We use (from
`union`

) instead of**Data.List**to avoid duplicated variable names in the result.`++`

`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`- Where we used
`lookup`**::****Eq**`key`**=>**[(`key`,`value`)]**->**`key`**->****Maybe**`value``fromJust`**::****Maybe**`a`**->**`a`

- Using means we let the function crash if it encounteres an unknown variable.
`fromJust`- Doing it this way is a quick hack. We will see a better solution later.

**data****Maybe**`a`**=****Nothing****|****Just**`a`- Useful for functions like that need to indicate success or failure.
`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`

- Implement
`diff`**::****Expr****->****Name****->****Expr**

- See Derivative rules.

`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- It works, but the resulting expressions need to be simplified!

- We want to avoid creating expressions ,
0

`+``e`,`e``+`0,0

`*``e`,`e``*`0,1

`*``e`...`e``*`1 - We can achieve this by using and
`add`everywhere instead of`mul`and**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`

- This helps a lot but more simplifications are needed...

- We can add more rules in the smart constructors and make them even smarter, but...
- A more systematic approach to might be better.
- See the self-study exercises for Week 5!

- 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 class
**Applicative**`evalA`(**Num**`n`)**=**`pure``n``evalA`(**Add**`a``b`)**=**`pure`(`+`)`<*>``evalA``a``<*>``evalA``b``evalA`(**Mul**`a``b`)**=**`pure`(`*`)`<*>``evalA``a``<*>``evalA``b`

- What is the type ?
`evalA`

`evalA`**::****Applicative**`f`**=>****Expr****->**`f`**Integer**- It works for
*any*type in theclass!**Applicative**- It also works for
*any*type in theclass (it's a subclass).**Monad**

- It also works for
- Example: is in the
**Maybe**class, so we can get**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 withor`<*>`, so I used the`=<<`notation.**do**

- Any function type is in
(

`e`**->**), so we can pass extra arguments.**Applicative** - We can make the environment implicit.
`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`

- 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 an instance of
**Eval**?**Monad**- Unfortunately not!

- 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`**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->EvalIntegerevalM(Numn)=purenevalM(Varx)=lookupVarxevalM(Addab)=(+)<$>evalMa<*>evalMbevalM(Mulab)=(*)<$>evalMa<*>evalMbevalM(Divab)=dox<-evalMay<-evalMbsafeDivxysafeDivx0=divByZerosafeDivxy=pure(x`div`y)

- 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 instead of
**Either**we could return informative error messages ("division by zero" or "undefined variable") instead of**Maybe**.**Nothing**- It only takes a few simple changes in the monad,
the function remains unchanged!
`evalM`

- It only takes a few simple changes in the monad,
the function