1 / 22

Transforming High-level Semantics into Low-level Implementations

This talk presents a new approach to transforming high-level semantics into low-level implementations. It introduces continuations and removes them in a purely calculational manner, resulting in a simplified and more direct process. The approach scales to various language features, such as exceptions, state, loops, and non-determinism.

inese
Download Presentation

Transforming High-level Semantics into Low-level Implementations

An Image/Link below is provided (as is) to download presentation Download Policy: Content on the Website is provided to you AS IS for your information and personal use and may not be sold / licensed / shared on other websites without getting consent from its author. Content is provided to you AS IS for your information and personal use only. Download presentation by click this link. While downloading, if for some reason you are not able to download a presentation, the publisher may have deleted the file from their server. During download, if you can't get a presentation, the file might be deleted by the publisher.

E N D

Presentation Transcript


  1. Background In his classic 1972 paper on definitional interpreters, John Reynolds introduced two key techniques: • Continuation-passing style- Makes control flow explicit • Defunctionalisation- Makes programs first-order

  2. Background These techniques are often used together: CPS DEFUN language compiler Can the two steps be fused together !? Introduce continuations Remove continuations

  3. This Talk • A new approach to transforming high-level semantics into low-level implementations; • Only requires simple calculation techniques, and avoids the use of continuations; • Scales to exceptions, state, variable binding, loops, non-determinism, interrupts, etc.

  4. 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

  5. Step 1 – Add Continuations Make the flow of control explicit by transforming the semantics into continuation-passing style. Definition: A continuation is a function that is applied to the result of another computation.

  6. Specification Aim: define a new semantics eval’ :: Expr  Cont  Int Cont = Int  Int such that eval’ e c = c (eval e)

  7. 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))) Original semantics: Control flow now explicit. eval e = eval’ e (n  n)

  8. Step 2 - Defunctionalise Make the semantics first-order again by applying the technique of defunctionalisation. Basic idea: Represent the continuations that we actually need using a datatype.

  9. Specification Aim: define a new semantics eval’’ :: Expr  CONT  Int such that exec :: CONT  Cont eval’’ e c = eval’ e (exec c)

  10. New semantics: eval’’ :: Expr  CONT  Int eval’’ (Val n) c = exec c n eval’’ (Add x y) c = eval’’ x (NEXT y c) exec :: CONT  Int  Int exec (NEXT y c) n = eval’’ y (ADD n c) exec (ADD n c) m = exec c (n + m) exec HALT n = n An abstract machine for evaluating expressions.

  11. Reflection We now have a two step process for calculating an abstract machine from a high-level semantics: 1 – Add a continuation 2 – Remove the continuations Can the steps be combined?

  12. The Trick Start directly with the combined specification: eval’’ e c exec c (eval e) = Aim to calculate definitions for eval’’, exec and CONT that satisfy these equations.

  13. In Practice • Calculating three interlinked definitions at the same time seems like an impossible task; • But... with experience gained from our stepwise approach, it turns out to be straightforward; • New calculation is simpler, more direct, and eliminates the use of continuations.

  14. Case: e = Add x y eval’’ (Add x y) c = exec c (eval (Add x y)) = exec c (eval x + eval y) But we are using induction, so we have induction hypotheses! Now we appear to be stuck, as no further definitions can be applied.

  15. To use the hypothesis for y, we need a term of form exec c’ (eval y) for some c’, i.e. we must solve: exec c’ (eval y) exec c (eval x + eval y) = We start by generalising to: exec c’ m exec c (n + m) = But we can’t simply use this as a definition for exec, because c and n are unbound.

  16. Solution Package the free variables up in the argument c’ by adding a new constructor to the CONT type, ADD :: Int  CONT  CONT and a new equation for the exec function: exec (ADD n c) m = exec c (n + m)

  17. Now we can continue: exec c (eval x + eval y) = exec (ADD (eval x) c) (eval y) = eval’’ y (ADD (eval x) c) = . . .

  18. Summary • The rest of the calculation of the abstract machine proceeds in a similar manner; • The driving force for the calculation is the desire to apply induction hypotheses; • We solve the resulting equations by adding new constructors to CONT on demand.

  19. Final Result data CONT where NEXT :: Expr  CONT  CONT ADD :: Int  CONT  CONT HALT :: CONT eval’’ (Val n) c = exec c n eval’’ (Add x y) c = eval’’ x (NEXT y c) exec (NEXT y c) n = eval’’ y (ADD n c) exec (ADD n c) m = exec c (n + m) exec HALT n = n

  20. Conclusion • Purely calculational approach to cutting out the intermediate use of continuations; • Only requires simple techniques, and scales to a wide variety of language features; • Can also be used to calculate compilers, and everything has been formalised in Coq.

More Related