Page 1

Page 2

Reflections on last week's lecture

We wrote a parser for arithmetic expressions

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

Arithmetic Expressions

Remember this from last week?

• ```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 4

Symbolic Expressions

How about expressions with variables in them?

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

type Name = String```
Page 5

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 6

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 key => [(key,value)] -> key -> Maybe value`
• 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 7

The Maybe type

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

Symbolic Differentiation

Page 9
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 10

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 11

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 12

Extending our simple calculator

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

• ```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.
Page 14

Improving the simple calculator

• 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 >