calculating an exceptional machine graham hutton and joel wright university of nottingham
TRANSCRIPT
CALCULATING ANEXCEPTIONAL MACHINE
Graham Hutton and Joel WrightUniversity of Nottingham
2
Exception
An event that causes a computation to terminate in a non-standard way.
Abstract Machine
A term-rewriting system for executing programs in a particular language.
3
This Talk
We show how to calculate an abstract machine for a small language with exceptions;
The key technique is defunctionalization, first introduced by John Reynolds in 1972;
Somewhat neglected in recent years, but now re-popularised by Olivier Danvy et al.
4
Arithmetic Expressions
data Expr = Val Int | Add Expr Expr
eval :: Expr Inteval (Val n) = neval (Add x y) = eval x + eval y
Syntax:
Semantics:
5
Step 1 - Add Continuations
Make the evaluation order explicit, by rewriting the semantics in continuation-passing style.
Definition:
A continuation is a function that is applied to the result of another
computation.
6
Example:
Basic idea:
Generalise the semantics to make the use of continuations
explicit.
eval x + eval y
continuation
computation
7
Aim: define a new semantics
and hence
eval’ :: Expr (Int Int) Int
eval e = eval’ e (n n)
eval’ e c = c (eval e)
such that
8
eval’ (Add x y) c
Case: e = Add x y
c (eval (Add x y))=
c (eval x + eval y)=
eval’ x (n eval’ y (m c (n+m))=
eval’ x (n (m c (n+m)) (eval y))=
eval’ x (n c (n + eval y))=
(n c (n + eval y)) (eval x)=
c (eval (Add x y))
c (eval x + eval y)
eval’ x (n (m c (n+m)) (eval y))
eval’ x (n c (n + eval y))
(n c (n + eval y)) (eval x)
9
eval’ :: Expr Cont Int
eval’ (Val n) c = c n
eval’ (Add x y) c = eval’ x (n
eval’ y (m
c (n+m)))
New semantics:
The evaluation order is now explicit.
10
Step 2 - Defunctionalize
Make the semantics first-order again, by rewriting eval’ using the defunctionalization technique.
Basic idea:
Represent the continuations we actually need using a
datatype.
11
Continuations:
eval’ :: Expr Cont Int
eval’ (Val n) c = c n
eval’ (Add x y) c =
eval’ x (n eval’ y (m c (n+m)))
eval :: Expr Int
eval e = eval’ e (n n)(n n)
(m c (n+m))(n eval’ y (m c (n+m)))
12
Combinators:
c2 :: Expr Cont Cont
c2 y c = n eval’ y (c3 n c)
c1 :: Cont
c1 = n n
c3 :: Int Cont Cont
c3 n c = m c (n+m)
13
Datatype:
apply :: CONT Cont
apply C1 = c1
apply (C2 y c) = c2 y (apply c)
apply (C3 n c) = c3 n (apply c)
data CONT = C1
| C2 Expr CONT
| C3 Int CONT
Semantics:
14
Aim: define a function
and hence
eval’’ e c = eval’ e (apply c)
eval e = eval’’ e C1
such that
eval’’ :: Expr CONT Int
15
eval’’ (Val n) c = apply c n
eval’’ (Add x y) c = eval’’ x (C2 y c)
By calculation, we obtain:
The semantics is now first-order again.
apply C1 n = n
apply (C2 y c) n = eval’’ y (C3 n c)
apply (C3 n c) m = apply c (n+m)
16
Step 3 - Refactor
What have we actually produced?
Question:
An abstract machine, but this only becomes clear after we refactor the components.
Answer:
17
data Cont = STOP | EVAL Expr Cont | ADD Int Cont run e = eval e STOP
eval (Val n) c = exec c neval (Add x y) c = eval x (EVAL y c)
exec STOP n = nexec (EVAL y c) n = eval y (ADD n c)exec (ADD n c) m = exec c (n+m)
Abstract machine:
18
Example:
run (Add (Val 1) (Val 2))
eval (Add (Val 1) (Val 2)) STOP=
eval (Val 1) (EVAL (Val 2) STOP)=
exec 3 STOP=
exec (ADD 1 STOP) 2=
eval (Val 2) (ADD 1 STOP)=
exec (EVAL (Val 2) STOP) 1=
3=
19
eval :: Expr Maybe Inteval (Val n) = Just neval (Throw) = Nothingeval (Add x y) = eval x eval yeval (Catch x y) = eval x eval y
Adding Exceptions
data Expr = ••• | Throw | Catch Expr Expr
Syntax:
Semantics:
20
Step 1 - Add Continuations
Step 2 - Defunctionalize
Step 3 - Refactor
Make evaluation order explicit.
Make first-order once again.
Reveal the abstract machine.
21
Control stack:
Evaluating an expression:
data Cont = STOP | EVAL Expr Cont | ADD Int Cont | HAND Expr Cont
eval :: Expr Cont Maybe Inteval (Val n) c = exec c neval (Throw) c = unwind ceval (Add x y) c = eval x (EVAL y c)eval (Catch x y) c = eval x (HAND y c)
22
Executing the control stack:
Unwinding the control stack:
unwind :: Cont Maybe Int unwind STOP = Nothingunwind (EVAL _ c) = unwind cunwind (ADD _ c) = unwind cunwind (HAND y c) = eval y c
exec :: Cont Int Maybe Int exec STOP n = Just nexec (EVAL y c) n = eval y (ADD n c)exec (ADD n c) m = exec c (n+m)exec (HAND _ c) n = exec c n
23
Summary
Purely calculational development of an abstract machine for a language with exceptions;
Key ideas of marking/unmarking and unwinding the stack arise directly from the calculations;
Techniques have been used to systematically design many other machines - Danvy et al.
24
Further Work
Exploiting monads and folds;
Reasoning about efficiency;
Generalising the language;
Calculating a compiler.