You are on page 1of 8

COMS22201: Language Engineering

Lab Exercises: Week 18-19


This worksheet is released in (reading) week 18 for discussion at the lab

in week 19. You are expected to spend 5-6 hours in total working on these
exercises. The more you can do on your own before the lab session the better.
During the lab you are encouraged to discuss your work in small groups. Aim
to finish all essential questions and try some of the additional ones. Practice
writing up your answers as if you are answering an exam.

Essential Questions
1. This question will help you to implement the denotational semantics
of While Statements as defined in Chapter 4 of Nielsons book. In
particular, the following steps will enable you to port the Miranda
code in Appendix D of the book directly into Haskell (building on the
code you developed in the previous lab sheet).

(a) Define a syntactic class for program statements by introducing the

following type constructors:
data Stm = Ass Var Aexp | Skip | Comp Stm Stm |
If Bexp Stm Stm | While Bexp Stm
deriving (Show, Eq, Read)
(b) Define a constant p::Stm that represents the following program
(which computes in y the factorial of the initial x):
while (x=1) do

p :: Stm
p = (Comp
(Ass "y" (N 1))
(Neg (Eq (V "x") (N 1)))
(Ass "y" (Mult (V "y") (V "x")))
(Ass "x" (Sub (V "x") (N 1)))

(c) Define a function update::State->Z->Var->State such that a

call update s i v returns the updated state s[v 7 i].

update :: State -> Z -> Var -> State

update s v x y
| x == y = v
| otherwise = s y

(d) Define a state s::State by updating the state s::State from

last week so it maps the variable x to the value 5.

s :: State
s = update s 5 "x"

(e) Now, define a function cond::(a->T, a->a, a->a)->(a->a) that

implements the auxiliary conditional semantic function cond :
(a T ) (a a) (a a) (a a).

cond :: (a->T, a->a, a->a) -> (a->a)

cond (p, g1, g2) s
| p s = g1 s
| otherwise = g2 s

(f) Use the following standard Haskell definition of a fixpoint in order

to implement the auxiliary semantic least fixpoint operator F IX :
((State , State) (State , State)) (State , State):

fix :: ((State->State)->(State->State))->(State->State)
fix ff = ff (fix ff)
(g) Define a function s_ds::Stm->State->State that implements the
semantic function Sds J.K : Stm (State , State) for the state-
ments of While.
s_ds :: Stm -> State -> State
s_ds (Ass x a) s = update s (a_val a s) x
s_ds (Skip) s = s
s_ds (Comp ss1 ss2) s = ((s_ds ss2).(s_ds ss1)) s
s_ds (If b ss1 ss2) s = (cond (b_val b, s_ds ss1, s_ds ss2)) s
s_ds (While b ss) s = (fix ff) s
ff :: (State->State) -> (State->State)
ff g = cond (b_val b, g.s_ds ss, id)

(h) Evaluate the result of running program p in state s.

map (s_ds p s) ["x","y","z"] [1,120,3]

2. Explain whether Sds J.K is a partial or total function.

The semantic function Sds J.K is a total function as it maps each and
every statement S Stm to some state transformer g : State , State.
The state transformer g, however, may be a partial function as it could
be undefined on some (or even all) inputs (representing states from
which the program loops infinitely).
3. Prove that there can be at most one least fixpoint of any function
f : X X with respect to some partial order v on a set X.
4. Find the least fixpoint of the function f = (square half inc)
obtained by composing the real-valued operators square = x.(x x),
half = x.(x/2) and inc = x.(x + 1).

(  2 )
f ix f = {x | x = f x} = x|x=
x + 2x + 1
= x|x= = {x | x2 2x + 1 = 0}

= {x | (x 1)2 = 0} = {1}

Since there is only one fixpoint, this must be the least fixpoint (under
any partial ordering).

5. Give direct characterisations of the semantics of the following programs

(by repeatedly applying the definition of Sds J.K and rearranging until
all semantic brackets and auxiliary functions are eliminated):

(a) if (x0) then x:=x*(0-1) else skip

Sds Jif (x0) then x:=x*(0-1) else skipKs

= cond(BJx0K, Sds Jx:=x*(0-1)K, Sds JskipK)s
Sds Jx:=x*(0-1)Ks if BJx0Ks = tt
Sds JskipKs otherwise
s[x 7 AJx*(0-1)Ks] if AJxKs AJ0Ks
id s otherwise
s[x 7 AJxKs AJ0-1Ks] if s x 0
s otherwise
s[x 7 s x (AJ0Ks AJ1Ks)] if s x 0
s otherwise
s[x 7 s x (N J0K N J1K)] if s x 0
s otherwise
s[x 7 s x (0 1)] if s x 0
s otherwise

s[x 7 (s x)] if s x 0
s otherwise
= s[x 7 |s x| ]
i.e. x is updated with its modulus!
(b) while true do skip

Sds Jwhile true do skipK

= F IX g.cond(BJtrueK, g Sds JskipK, id)
= F IX g.g Sds JskipK
= F IX g.g id
= F IX g.g
= F IX id
n.b. since every state transformer is a fixpoint of this functional,
the least fixpoint with respect to subset inclusion on the function
graph is simply the empty set (i.e. the transformer undefined on
every state).

Additional Questions
6. Give a direct characterisation of the functionals of the following loops:

(a) while (x=0) do skip

(b) while (x=0) do x:=x-1
(c) while (x=1) do (y:=y*x; x:=x-1)

Find any fixpoints of the above and identify any least fixpoints.

(a) Sds Jwhile (x=0) do skipK = F IX F where
F g = cond(BJ(x=0)K, g Sds JskipK, id)
F g s = cond(BJ(x=0)K, g Sds JskipK, id) s
= cond(BJ(x=0)K, g id, id) s
= cond(BJ(x=0)K, g, id) s
g s if BJ(x=0)K s = tt
id s otherwise
g s if BJx=0K s = ff
s otherwise
g s if AJxK s 6= AJ0K s
s otherwise
g s if s x 6= N J0K
s otherwise
g s if s x 6= 0
s otherwise
So that
g f ix(F ) iff g = F g
iff g s = F g s for all s State
iff g s = F g s for all sx=0 and g s = F g s for all sx6=0
iff g s = s for all sx=0 and g s = g s for all sx6=0
iff g s = s for all sx=0
i.e. fixpoints of F are state transformers g : State , State which
behave like an identity on all states in which x is zero.
Examples include
i. g = id
ii. g s = s[x 7 (s x) 2]
s if s x = 0
iii. gs = (which is F IXF )
undef otherwise
But not
iv. g=
v. g s = s[x 7 (s x) 1]


7. Show that the following pairs of statements are semantically equivalent

(a) S;skip and S.

(b) S1;(S2;S3) and (S1;S2);S3


8. Explain exactly how the query fac 5 is evaluated by Haskell when

applied to the following fixpoint definition of the factorial function:

fac = fix (\f n -> if n == 0 then 1 else n * f (n-1))

fac 5
(fix ff) 5
ff (fix ff) 5
5 * (fix ff) 4
5 * ff (fix ff) 4
5 * 4 * (fix ff) 3
5 * 4 * ff (fix ff) 3
5 * 4 * 3 * (fix ff) 2
5 * 4 * 3 * ff (fix ff) 2
5 * 4 * 3 * 2 * (fix ff) 1
5 * 4 * 3 * 2 * ff (fix ff) 1
5 * 4 * 3 * 2 * 1 * (fix ff) 0
5 * 4 * 3 * 2 * 1 * ff (fix ff) 0
5 * 4 * 3 * 2 * 1 * 1
1 if n = 0
Note that if we define F = f.n.
n f (n 1) otherwise
1 if n = 0
Then any fixpoint f of F must satisfy f = n.
n f (n 1) otherwise

Which means any fixpoint f of F must compute factorials. But here
are many such fixpoints because there is some flexibility about what
values to return for negative n. For example we can set f of all negative
numbers to 0 or undef (as in case of the least fixpoint with respect to
subset inclusion on the function graph).
Equivalently F can be seen as a function that takes an approximant to
the factorial function and returns a better approximation. For example,
we could take id as an initial approximation which gets two outputs
correct (1! and 2!). But F id is a better approximation as it gets three
correct (0!, 2! and 3!). Carrying on F n id gets n + 2 values correct.
Alternatively we could start with , which gets no values correct! But
F n gets n values correct. Classic mathematical results, such as the
Kleene fixpoint theorem, can be used to show that the least fixpoint of
F is in fact equal to F .