2018-11-25 17:30
Page 1

Page 2

# Modelling Arithmetic Expressions

• 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...
Page 3
##### Modelling Arithmetic Expressions
• Use a datatype that reflects the structure of arithmetic expressions
• An expressions can be
• a number n
• a multiplication a*b
• where a and b are subexpressions
Page 4

Page 5

# Modelling Arithmetic Expressions

• As a Haskell data type
• ```data Expr = Num Integer
| Mul Expr Expr```
• Note: it's recursive.
• Examples:
2
`Num 2`
2+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))`
Page 6

# Example: Evaluation

• Define a function
• `eval :: Expr -> Integer`
• that computes the value of an expression.
• Example:
`eval (Add (Num 1) (Mul (Num 2) (Num 3)))`
==>
`7`
Page 7
##### Example: Evaluation
```eval :: Expr -> Integer
eval (Num n) = n
eval (Add a b) = eval a + eval b
eval (Mul a b) = eval a * eval b```
Page 8

# Showing Expressions

• ```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"
Page 9

• 1+(2+3)
• 1+(2*3)
• 1*(2+3)
Page 10

# Showing expressions with brackets

```showExpr :: Expr -> String
showExpr (Num n) = show n
showExpr (Add a b) = showExpr a ++ "+" ++ showExpr b
showExpr (Mul a b) = showFactor a++"*"++showFactor b

showFactor :: Expr -> String
showFactor e = showExpr e```
Page 11

# Making a Show instance

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

# Generating arbitrary expressions

• 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 = (...)
```
Page 13

# Completing the arithmetic quiz program

```main =
do putStrLn "Welcome to the Arithmetic Quiz!"
forever quiz

quiz =
do e <- generate (rExpr 3)
putStr ("\n"++show e++" = ")
let correct = show (eval e)
putStrLn
then "Correct!"
else "Wrong! The correct answer is: "
++ correct)
```
Page 14

# Symbolic Expressions

Page 15
##### Symbolic Expressions

• ```data Expr = Num Integer
| 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
Page 16

## How about expressions with variables in them?

```data Expr = Num Integer
| Var Name       -- new
| Mul Expr Expr

type Name = String```
Page 17

# Gathering variables

• 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
`union`
(from `Data.List`) instead of
`++`
to avoid duplicated variable names in the result.
Page 18

# Substitution

## Replacing variables with something else

• ```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?
Page 19

# Evaluating Symbolic Expressions

• ```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
`error`
means we let the function crash if it encounteres an unknown variable.
• Alternatively, we could return a default value, e.g.
`0`
.
• To handle undefined variables more gracefully, we could change the return type of
`eval`
to
`Maybe Integer`
Page 20

# The Maybe type

• `data Maybe a = Nothing | Just a`
• Useful for functions like
`lookup`
that need to indicate success or failure.
• ```lookup :: Eq k => [(k,v)] -> k -> Maybe v
lookup k [] = Nothing
lookup k ((k',v):kvs) | k' == k   = Just v
| otherwise = lookup k kvs```
Page 21

# Symbolic Differentiation

Page 22
##### Symbolic Differentiation
• ```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!
Page 23

# Smart constructors

• We want to avoid creating expressions
`0+e`
,
`e+0`
,
`0*e`
,
`e*0`
,
`1*e`
,
`e*1`
...
• We can achieve this by using
`add`
and
`mul`
`Add`
and
`Mul`
• ```add (Num 0) b = b
add a (Num 0) = a
• ```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...
Page 24

# Simplifying expressions

• 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!
Page 25

# Summary

• 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.
Page 26

# Next time

• Today we defined
• `showExpr :: Expr -> String`
• Next time: how to write parsers:
• `readExpr :: String -> Expr`