240 likes | 351 Views
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. This Talk. We show how to calculate an abstract machine for a small language with exceptions;
E N D
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.
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.
Arithmetic Expressions Syntax: data Expr = Val Int | Add Expr Expr Semantics: eval :: Expr Int eval (Val n) = n eval (Add x y) = eval x + eval y
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.
eval x + eval y computation continuation Example: Basic idea: Generalise the semantics to make the use of continuations explicit.
Aim: define a new semantics eval’ :: Expr (Int Int) Int such that eval’ e c = c (eval e) and hence eval e = eval’ e (n n)
= c (eval (Add x y)) = c (eval x + eval y) = (n c (n + eval y)) (eval x) = eval’ x (n c (n + eval y)) = eval’ x (n (m c (n+m)) (eval y)) = eval’ x (n eval’ y (m c (n+m)) Case: e = Add x y eval’ (Add x y) c c (eval (Add x y)) c (eval x + eval y) (n c (n + eval y)) (eval x) eval’ x (n c (n + eval y)) eval’ x (n (m c (n+m)) (eval y))
New semantics: eval’ :: Expr Cont Int eval’ (Val n) c = c n eval’ (Add x y) c = eval’ x (n eval’ y (m c (n+m))) The evaluation order is now explicit.
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.
Continuations: eval :: Expr Int eval e = eval’ e (n n) (n n) eval’ :: Expr Cont Int eval’ (Val n) c = c n eval’ (Add x y) c = eval’ x (n eval’ y (m c (n+m))) (n eval’ y (m c (n+m))) (m c (n+m))
Combinators: c1 :: Cont c1 = n n c2 :: Expr Cont Cont c2 y c = n eval’ y (c3 n c) c3 :: Int Cont Cont c3 n c = m c (n+m)
Datatype: data CONT = C1 | C2 Expr CONT | C3 Int CONT Semantics: apply :: CONT Cont apply C1 = c1 apply (C2 y c) = c2 y (apply c) apply (C3 n c) = c3 n (apply c)
Aim: define a function eval’’ :: Expr CONT Int such that eval’’ e c = eval’ e (apply c) and hence eval e = eval’’ e C1
By calculation, we obtain: eval’’ (Val n) c = apply c n eval’’ (Add x y) c = eval’’ x (C2 y c) apply C1 n = n apply (C2 y c) n = eval’’ y (C3 n c) apply (C3 n c) m = apply c (n+m) The semantics is now first-order again.
Step 3 - Refactor Question: • What have we actually produced? Answer: • An abstract machine, but this only becomes clear after we refactor the components.
Abstract machine: data Cont = STOP | EVAL Expr Cont | ADD Int Cont run e = eval e STOP eval (Val n) c = exec c n eval (Add x y) c = eval x (EVAL y c) exec STOP n = n exec (EVAL y c) n = eval y (ADD n c) exec (ADD n c) m = exec c (n+m)
= eval (Add (Val 1) (Val 2)) STOP = eval (Val 1) (EVAL (Val 2) STOP) = exec (EVAL (Val 2) STOP) 1 = eval (Val 2) (ADD 1 STOP) = exec (ADD 1 STOP) 2 = exec 3 STOP = 3 Example: run (Add (Val 1) (Val 2))
Adding Exceptions Syntax: data Expr = ••• | Throw | Catch Expr Expr Semantics: eval :: Expr Maybe Int eval (Val n) = Just n eval (Throw) = Nothing eval (Add x y) = eval xeval y eval (Catch x y) = eval x eval y
Step 1 - Add Continuations Make evaluation order explicit. Step 2 - Defunctionalize Make first-order once again. Step 3 - Refactor Reveal the abstract machine.
Control stack: data Cont = STOP | EVAL Expr Cont | ADD Int Cont | HAND Expr Cont Evaluating an expression: eval :: Expr Cont Maybe Int eval (Val n) c = exec c n eval (Throw) c = unwind c eval (Add x y) c = eval x (EVAL y c) eval (Catch x y) c = eval x (HAND y c)
Executing the control stack: exec :: Cont Int Maybe Int exec STOP n = Just n exec (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 Unwinding the control stack: unwind :: Cont Maybe Int unwind STOP = Nothing unwind (EVAL _ c) = unwind c unwind (ADD _ c) = unwind c unwind (HAND y c) = eval y c
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.
Further Work • Exploiting monads and folds; • Reasoning about efficiency; • Generalising the language; • Calculating a compiler.