2018-11-25 17:30

Page 1
- Imagine a program to help school children learn arithmetic:
- What is (1+2)*3?
`8`

Sorry, wrong answer!

- Expression like (1+2)*3 need to be treated as
*data*in this program.- We need to generate random expressions.
- We need show expressions to the user.
- We need to compute the values of expressions and compare with the answers that the user enters.

- Using strings might be possible, but will not make this easy...

- Use a datatype that reflects the structure of arithmetic expressions
- An expressions can be
- a number
`n` - an addition
`a`+`b` - a multiplication
`a`*`b`

- a number
- where
`a`and`b`are subexpressions

- Source code: ArithmeticQuiz.hs.

- As a Haskell data type
**data****Expr****=****Num****Integer****|****Add****Expr****Expr****|****Mul****Expr****Expr**- Note: it's
*recursive*.

- Examples:
Expression Haskell representation 2 **Num**22+2 **Add**(**Num**2) (**Num**2)(1+2)*3 **Mul**(**Add**(**Num**1) (**Num**2)) (**Num**3)1+2*3 **Add**(**Num**1) (**Mul**(**Num**2) (**Num**3))

- Define a function
`eval`**::****Expr****->****Integer**

- that computes the value of an expression.
- Example: ==>
`eval`(**Add**(**Num**1) (**Mul**(**Num**2) (**Num**3)))`7`

eval::Expr->Integereval(Numn)=neval(Addab)=evala+evalbeval(Mulab)=evala*evalb

`showExpr`**::****Expr****->****String**`showExpr`(**Num**`n`)**=**`show``n``showExpr`(**Add**`a``b`)**=**`showExpr``a``++`"+"`++``showExpr``b``showExpr`(**Mul**`a``b`)**=**`showExpr``a``++`"*"`++``showExpr``b`- Will this work? Testing it:
`showExpr (Mul (Num 1) (Add (Num 2) (Num 3)))`

"1*2+3"

- 1+(2+3)
- 1+(2*3)
- 1*(2+3)

showExpr::Expr->StringshowExpr(Numn)=shownshowExpr(Addab)=showExpra++"+"++showExprbshowExpr(Mulab)=showFactora++"*"++showFactorbshowFactor::Expr->StringshowFactor(Addab)="("++showExpr(Addab)++")"showFactore=showExpre

**instance****Show****Expr****where**`show`**=**`showExpr`- Remove from the list of derived instances:
**Show** **data****Expr**= ...**deriving**(**Eq**~~,Show~~)- Warning: since can make different expressions look the same, this might make debugging in GHCi more difficult in some situations…
`showExpr`

- First attempt
`rExpr_v1`**::****Gen****Expr**`rExpr_v1`**=**`oneof`[`rNum`,`rBin`]**where**`rNum`**=**`elements`[**Num**`n`**|**`n`**<-**[1**..**10]]`rBin`**=****do**`op`**<-**`elements`[**Add**,**Mul**]`e1`**<-**`rExpr_v1``e2`**<-**`rExpr_v1``return`(`op``e1``e2`)

- But we need better control over the size of the generated expressions...
`rExpr`**::****Int****->****Gen****Expr**`rExpr``size`**=**(`...`)

main=doputStrLn"Welcome to the Arithmetic Quiz!"foreverquizquiz=doe<-generate(rExpr3)putStr("\n"++showe++" = ")answer<-getLineletcorrect=show(evale)putStrLn(ifanswer==correctthen"Correct!"else"Wrong! The correct answer is: "++correct)

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

`substitute`**::**[(**Name**,**Integer**)]**->****Expr****->****Expr**`substitute`**::**[(**Name**,**Expr**)]**->****Expr****->****Expr**`substitute`**::**(**Name****->****Integer**)**->****Expr****->****Expr**`substitute`**::**(**Name****->****Expr**)**->****Expr****->****Expr**- Which variant is more useful/general?

`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**`k`**=>**[(`k`,`v`)]**->**`k`**->****Maybe**`v`

- 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**`k`**=>**[(`k`,`v`)]**->**`k`**->****Maybe**`v``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!

- Recursive datatypes can take many forms other than lists.
- Recursive datatypes can model
*languages*(expressions, natural languages, programming languages). - Functions working with recursive types are often recursive themselves (program structure follows data structure).
- When generating random elements in recursive datatype, think about the
*size*.

- Today we defined
`showExpr`**::****Expr****->****String**

- Next time: how to write
*parsers*:`readExpr`**::****String****->****Expr**