Lecture 6 (2018-02-01)
WhileNZ
We started defining a simple imperative language, which we called
WhileNZ. Here's its syntax and semantics:
```
n in Nat
v in Var (some set of variables)
e in Expr ::= n | e1 plus e2 | e1 times e2 | neg e | x
c in Command ::= SKIP | c1 ; c2 | x := e | WHILENZ e DO c END
sigma in Store, the set of total functions assigning ints to variables
i.e. Var -> Z
(sigma[x |-> z])(y) = / z if x = y
\ sigma(y) otherwise
eval : Store -> Expr -> Z
eval(sigma, n) = n
eval(sigma, e1 plus e2) = eval(sigma, e1) + eval(sigma, e2)
eval(sigma, e1 times e2) = eval(sigma, e1) * eval(sigma, e2)
eval(sigma, neg e) = -eval(sigma, e)
eval(sigma, x) = sigma(x)
interp : Store -> Command -> Store
interp(sigma, SKIP) = sigma
interp(sigma, c1 ; c2) = interp(interp(sigma, c1), c2)
interp(sigma, x := e) = sigma[x|->eval(sigma, e)]
interp(sigma, WHILENZ e DO c END) =
if eval(sigma, e) = 0
then sigma
else interp(interp(sigma, c), WHILENZ e DO c)
```
We went over an example or two in class, running some loops and
observing that sometimes `interp` wasn't well defined, i.e., sometimes
it ran forever, which isn't the sort of thing that math is supposed to
do.
Try running `interp` on the following programs... what do they do? Do
they always terminate? If so, what values will you get out?
```
Y := 5;
X := 1;
WHILENZ Y DO
X := Y * X;
Y := Y - 1
END
```
What will `X` be? What about `Y`?
```
A := X;
WHILENZ A DO
B := B + 1
END
```
What values will `A`, `B` and `X` have?
```
X := 1;
WHILENZ X DO
X := X + 1
END
```
## A simple interpreter

Here's how to write an interpreter for our simple language consisting
of arithmetic expressions, assignments, and loops.
The first order of business is thinking about variables: how should
we represent them? Haskell's map type seems like a good bet.
> import qualified Data.Map as Map
> import Data.Map (Map, (!))
>
> type VarName = String
>
> type Store = Map VarName Int
>
> update :: VarName -> Int -> Store -> Store
> update v n st = Map.insert v n st
### Arithmetic expressions

We return to our old friend, `ArithExp`, adding a notion of variable.
> data ArithExp =
> Num Int
> | Var VarName
> | Plus ArithExp ArithExp
> | Times ArithExp ArithExp
> | Neg ArithExp
> deriving (Show, Eq)
>
> evalA :: Store -> ArithExp -> Int
> evalA st (Var x) = st ! x -- Map.findWithDefault ?
> evalA _ (Num n) = n
> evalA st (Plus e1 e2) = evalA st e1 + evalA st e2
> evalA st (Times e1 e2) = evalA st e1 * evalA st e2
> evalA st (Neg e) = - (evalA st e)
The interpreter is pretty similar to our old one, but note that we
take an extra argument, `st :: Store`. The store is where we look for
variables. If a variable isn't in the store, then `Map.!` will
complain with an error.
### Commands in `WhileNZ`

Having converted the mathematical grammar:
```pre
s ::= skip | x := a | s1;s2 | while a s
```
To a Haskell datatype:
> data WhileNZ =
> Skip
> | Assign VarName ArithExp
> | Seq WhileNZ WhileNZ
> | WhileNZ ArithExp WhileNZ
> deriving Show
Let's set about writing our interpreter. While `evalA :: Store ->
ArithExp -> Int`, here `eval` takes a `Store` and a statement and
returns a new store.
> eval :: Store -> WhileNZ -> Store
> eval st Skip = st
> eval st (Assign x e) = update x (evalA st e) st
> eval st (Seq c1 c2) = eval (eval st c1) c2
> eval st eLoop@(WhileNZ e c) =
> if evalA st e == 0
> then st
> else eval (eval st c) eLoop
We can try writing a program or two...
> p1, p2 :: WhileNZ
> p1 = Seq (Assign "x" (Plus (Var "x") (Num 1)))
> (Assign "y" (Plus (Var "y") (Num (-1))))
> p2 = Seq (Assign "y" (Num 5))
> (Seq (Assign "x" (Num 0))
> (WhileNZ (Var "y") p1))
...and then we can run them in a sample store:
> stXY :: Store
> stXY = Map.fromList [("x",0),("y",0)]