Resugaring: Lifting Evaluation Sequences through Syntactic Sugar
Justin Pombrio, Shriram Krishnamurthi Brown University Syntactic Sugar
2 Syntactic Sugar x + 2 desugar x.__add__(2)
3 Syntactic Sugar x + 2 desugar x.__add__(2)
[x*x | x <- lst] desugar map (\x -> x*x) lst
4 Syntactic Sugar x + 2 desugar x.__add__(2)
[x*x | x <- lst] desugar map (\x -> x*x) lst x or y desugar let t = x in if t then t else y
5 Surface language (what you write) Syntactic Sugar x + 2 desugar x.__add__(2)
[x*x | x <- lst] desugar map (\x -> x*x) lst
x or y desugar let t = x in if t then t else y
6 Surface language Core language (what you write) Syntactic Sugar (what runs) x + 2 desugar x.__add__(2)
[x*x | x <- lst] desugar map (\x -> x*x) lst
x or y desugar let t = x in if t then t else y
7 Big surface language
desugar
Small core
8 Big surface language
desugar
Small core
9 Big surface language
desugar Code analyzer Small core Refactoring engine
Evaluator
10 Big surface language
desugar Code analyzer Small core Refactoring engine
Evaluator
11 Big surface language
desugar Code analyzer Small core Refactoring engine
Evaluator
12 Surface Core not(true) or true
13 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
14 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
let t = false in if t then t else true
if false then false else true
true
15 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
false or true let t = false in if t then t else true
if false then false else true
true true
16 Confection core eval seq → surface eval seq
17 18 92 steps
19 92 steps
7 steps
20 Surface Core not(true) or true
Resugaring: Running sugar in reverse
21 Surface Core not(true) or true
false or true
true
Resugaring: Running sugar in reverse
22 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
false or true
true
Resugaring: Running sugar in reverse
23 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
false or true let t = false in if t then t else true
if false then false else true
true true
Resugaring: Running sugar in reverse
24 Surface Core desugar not(true) or true let t = not(true) in resugar if t then t else true
false or true let t = false in if t then t else true
if false then false else true
true true
Resugaring: Running sugar in reverse
25 Surface Core desugar not(true) or true let t = not(true) in resugar if t then t else true
resugar false or true let t = false in if t then t else true
if false then false else true
true true
Resugaring: Running sugar in reverse
26 Surface Core desugar not(true) or true let t = not(true) in resugar if t then t else true
resugar false or true let t = false in if t then t else true
resugar if false then false else true
true true
Resugaring: Running sugar in reverse
27 THREE KEY PROPERTIES OF RESUGARING
28 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
resugar let t = false in if t then t else true
29 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
true or true resugar let t = false in or true if t then t else true
30 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
true or true resugar let t = false in or true if t then t else true
Emulation
Each surface term must desugar to the core term it purports to represent
31 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
resugar let t = false in if t then t else true
32 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
let t = false in resugar let t = false in if t then t else true if t then t else true
33 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
let t = false in resugar let t = false in if t then t else true if t then t else true
Abstraction
Show things in terms of a sugar precisely when the programmer used that sugar.
34 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
resugar let t = false in if t then t else true
resugar if false then false else true
resugar true true
35 Surface Core desugar not(true) or true let t = not(true) in if t then t else true
Coverage resugar let t = false in if t then t else true Show as many steps resugar as possible if false then false else true
resugar true true
36 x or y -> let t = x in if t then t else y
37 expand match substitute x or y -> let t = x in if t then t else y
38 expand match substitute x or y -> let t = x in if t then t else y substitute match
unexpand
39 A Little Theory
expand : Surf Term → Core Term unexpand : Core Term × Surf Term → Surf Term
40 A Little Theory
expand : Surf Term → Core Term unexpand : Core Term × Surf Term → Surf Term It's a lens!
41 A Little Theory
expand : Surf Term → Core Term unexpand : Core Term × Surf Term → Surf Term It's a lens! unexpand (expand T) T = T GetPut GetPut expand (unexpand T’ T) = T’ PutGet PutGet
42 A Little Theory
expand : Surf Term → Core Term unexpand : Core Term × Surf Term → Surf Term It's a lens! unexpand (expand T) T = T GetPut GetPut expand (unexpand T’ T) = T’ PutGet PutGet
Well-formedness criteria on rules ensure these laws.
43 Key Properties
Emulation
Abstraction
Coverage
44 Key Properties
Emulation (Lens Laws)
Abstraction
Coverage
45 Key Properties
Emulation (Lens Laws)
Abstraction (Tagging – see paper)
Coverage
46 Key Properties
Emulation (Lens Laws)
Abstraction (Tagging – see paper)
Coverage (Empirical)
47 A WORKING SYSTEM
48 92 steps
7 steps
49 Surface Core (or (and #t #f) #f)
50 Surface Core desugar (or (and #t #f) #f) ((lambda (t) (begin (if t t ((lambda () #f))))) (if #t ((lambda () #f)) #f))
51 Surface Core desugar (or (and #t #f) #f) ((lambda (t) (begin (if t t ((lambda () #f))))) (if #t ((lambda () #f)) #f))
((lambda (t) (begin (if t t ((lambda () #f))))) ((lambda () #f)))
((lambda (t) (begin (if t t ((lambda () #f))))) #f)
(if #f t ((lambda () #f)))
((lambda () #f))
#f
52 Surface Core desugar (or (and #t #f) #f) ((lambda (t) (begin (if t t ((lambda () #f))))) (if #t ((lambda () #f)) #f))
(or #f #f) ((lambda (t) (begin (if t t ((lambda () #f))))) ((lambda () #f)))
(or #f) ((lambda (t) (begin (if t t ((lambda () #f))))) #f)
(if #f t ((lambda () #f)))
((lambda () #f))
#f #f
53 Surface Core my-list = [2] cases(List) my-list: | empty() => print("empty") | link(something, _) => print("not empty") end
54 Surface Core my-list = [2] desugar my-list = list.["link"](2, list.["empty"]) cases(List) my-list: block: | empty() => print("empty") tempMODRIOUJ :: List = my-list | link(something, _) => tempMODRIOUJ.["_match"]({ print("not empty") "empty" : fun(): print("empty") end, end "link" : fun(something, _): print("not empty") end }, fun(): raise("cases: no cases matched") end) end
55 Surface Core my-list = [2] desugar my-list = list.["link"](2, list.["empty"]) cases(List) my-list: block: | empty() => print("empty") tempMODRIOUJ :: List = my-list | link(something, _) => tempMODRIOUJ.["_match"]({ print("not empty") "empty" : fun(): print("empty") end, end "link" : fun(something, _): print("not empty") end }, fun(): raise("cases: no cases matched") end) end
my-list = obj.["link"](2, list.["empty"]) my-list =
my-list = obj.["link"](2, list.["empty"]) my-list = [2] block: block: tempMODRIOUJ :: List = my-list tempMODRIOUJ :: List = my-list tempMODRIOUJ.["_match"]({"empty" : fun(): print("empty") end, tempMODRIOUJ.["_match"]({"empty" : fun(): print("empty") "link" : fun(something, _): print("not empty") end}, fun(): end, "link" : fun(something, _): print("not empty") end}, raise("cases: no cases matched") end) fun(): raise("cases: no cases matched") end) end end
my-list =
"not empty" 56 Surface Core my-list = [2] desugar my-list = list.["link"](2, list.["empty"]) cases(List) my-list: block: | empty() => print("empty") tempMODRIOUJ :: List = my-list | link(something, _) => tempMODRIOUJ.["_match"]({ print("not empty") "empty" : fun(): print("empty") end, end "link" : fun(something, _): print("not empty") end my-list = [2] }, cases(List) my-list: fun(): raise("cases: no cases matched") end) | empty() => print("empty") end my-list = obj.["link"](2, list.["empty"]) my-list =
"not empty" 57 1. Redex semantics engineering tool
2. Racket (racket.org)
3. Pyret (pyret.org)
58 t in y u rl Resugaring .c o m / The Confection tool re s ● u Declarative sugar specification g a ● Language agnostic r ● Guarantees Emulation and Abstraction
Current/future work ● Hygiene! ● Better error messages through resugaring
59 60 BACKUP SLIDES
61 How should this resugar? let t = not(true) in if t then t else true
Looks like the desugaring of an ‘or’.
But maybe the user wrote it?
62 Surface Core desugar or not(true) or false let t = not(true) in if t then t else false
resugar or false or false let t = false in if t then t else false
resugar if false then false else false
resugar false false
63 Surface Core desugar s1 c1
resugar c2 How do we make this transparent? resugar s2 c3 … … val val
64 Reconstruct the (core) program as source at each evaluation step (along with its tags).
Either instrument the compiler or do a pre-compilation step
CPS/ANF makes this easier; or just statefully keep track of the stack
65 Max([]) -> Raise(“empty list”);
Max(xs) -> MaxAcc(xs, -infinity);
Surface Max2 Core
Max([-infinity]) desugar MaxAcc([-infinity], -infinity)
Max2 Max([]) resugar MaxAcc([], -infinity)
66 Related Work
• J. Hennessy. Symbolic debugging of optimized code. Transactions on Programming Languages and Systems, 4(3), 1982. • J. Clements, M. Flatt, and M. Felleisen. Modeling an algebraic stepper. In European Symposium on Programming Languages and Systems, 2001. • R. Perera, U. A. Acar, J. Cheney, and P. B. Levy. Functional programs that explain their work. In International Conference on Functional Programming, 2012 • A. V. Deursen, P. Klint, and F. Tip. Origin tracking. Journal of Symbolic Computation, 15(5–6), 1993.
67