- We saw that by using a
*parsing combinator library*we could- Reduce the code size for the parser dramatically.
- Reduce the risk of making mistakes by abstracting away from tedious details.

- While parser generators (like Yacc, Happy, BNF) provide a
*domain-specific language*(DSL) for creating parsers… - …the
*parsing combinator library*can be seen as an*embedded domain-specific language*(EDSL) for creating parsers in Haskell.- It's just a library, not a language extension or separate language.
- This illustrates a key strenth of Functional Programming.
- Enabled by
*higher-order functions*,*polymorphism*,*data types*,*type classes*,*monads*and*laziness*.

- Enabled by

**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`- Can we extend it to support expressions containing variables?
- Live demo: SymbolicExpressions.hs

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`)**=****case**`lookup``x``env`**of****Just**`n`**->**`n`**Nothing****->**`error`("undefined variable: "`++``x`)`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`

- Calling means we let the function crash if it encounteres an unknown variable.
`error`- Alternatively, we could return a default value, e.g. .
`0`

- To handle undefined variables more gracefully, we could change the
return type of to
`eval`. (We will return to this later.)**Maybe****Integer**

- Alternatively, we could return a default value, e.g.

**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 might be better.
- See the self-study exercises for Week 5!

- Welcome to the simple calculator! >
`x = 1+2`

>`y = x*4`

>`x+y`

18 - We need a type and parser for commands
**data****Command****=****Define****Name****Expr****|****Eval****Expr**`command`**::****Parser****Command**`command`**=**(`...`)

`main`**::****IO**()`main`**=****do**`putStrLn`"Welcome to the simple calculator!"`repl`[]`repl`**::**[(**Name**,**Integer**)]**->****IO**()`repl``env`**=****do**`putStr`"> "`s`**<-**`getLine`**case**`completeParse``command``s`**of****Just**(**Define**`n``e`)**->**`repl`((`n`,`eval``env``e`)**:**`env`)**Just**(**Eval**`e`)**->****do**`print`(`eval``env``e`)`repl``env`**_****->****do**`putStrLn`"Syntax error!"`repl``env`- See SymbolicExpressions.hs for more details.

- We could improve the error handling
- Welcome to the simple calculator! >
`2*x`

*** Exception: undefined variable: x - While syntax errors are handled gracefully, undefined variables crash the calculator.

- We could add a command to differentiate expressions.
- Welcome to the simple calculator! >
`D x 2*x*x+3*y`

4*x >