Presentation is loading. Please wait.

Presentation is loading. Please wait.

A Fix for Dynamic Scope Ravi Chugh U. of California, San Diego.

Similar presentations


Presentation on theme: "A Fix for Dynamic Scope Ravi Chugh U. of California, San Diego."— Presentation transcript:

1 A Fix for Dynamic Scope Ravi Chugh U. of California, San Diego

2 Backstory 2 Goal: Types for “Dynamic” Languages Core λ-Calculus + Extensions Syntax and Semantics of JavaScript Translation à la Guha et al. (ECOOP 2010)

3 Backstory 3 Goal: Types for “Dynamic” Languages Core λ-Calculus + Extensions Approach: Type Check Desugared Programs Simple Imperative, Recursive Functions are Difficult to Verify

4 4 Translate to statically typed calculus? var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); } };

5 let fact = λn. if n <= 1 then 1 else n * fact(n-1) Option 1: λ-Calculus (λ) 5 Translate to statically typed calculus? var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); } }; fact is not bound yet… ✗

6 let fact = fix (λfact. λn. if n <= 1 then 1 else n * fact(n-1) ) Desugared fact should be mutable… Option 2: λ-Calculus + Fix (λ fix ) 6 Translate to statically typed calculus? var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); } }; ✗

7 let fact = ref (fix (λfact. λn. if n <= 1 then 1 else n * fact(n-1) )) Recursive call doesn’t go through reference… Okay here, but prevents mutual recursion Option 3: λ-Calculus + Fix + Refs (λ fix,ref ) 7 Translate to statically typed calculus? var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); } }; ✗

8 let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1) ) Yes, this captures the semantics! But how to type check ??? Option 4: λ-Calculus + Fix + Refs (λ ref ) 8 Translate to statically typed calculus? var fact = function(n) { if (n <= 1) { return 1; } else { return n * fact(n-1); } }; ✓

9 let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1) ) 9

10 10 let fact = ref (λn. 0) in fact := λn. if n <= 1 then 1 else n * !fact(n-1) ; Backpatching Pattern in λ ref fact :: Ref (Int  Int) Assignment relies on and guarantees the reference invariant

11 11 let fact = ref (λn. 0) in fact := λn. if n <= 1 then 1 else n * !fact(n-1) ; Backpatching Pattern in λ ref But we want to avoid initializers to: Facilitate JavaScript translation Have some fun! Simple types suffice if reference is initialized with dummy function…

12 Proposal: Open Types for λ ref 12 let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1) ) fact :: (fact :: Ref (Int  Int))  Ref (Int  Int) Assuming fact points to an integer function, fact points to an integer function

13 Proposal: Open Types for λ ref 13 let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1) ) in !fact(5) fact :: (fact :: Ref (Int  Int))  Ref (Int  Int) Assuming fact points to an integer function, fact points to an integer function Type system must check assumptions at every dereference

14 Proposal: Open Types for λ ref 14 let fact = ref (λn. if n <= 1 then 1 else n * !fact(n-1) ) Motivated by λ ref programs that result from desugaring JavaScript programs

15 Proposal: Open Types for λ ref 15 Motivated by λ ref programs that result from desugaring JavaScript programs let fact = λn. if n <= 1 then 1 else n * fact(n-1) Proposal also applies to, and is easier to show for, the dynamically-scoped λ-calculus (λ dyn ) Bound at the time of call… No need for fix or references

16 Lexical vs. Dynamic Scope 16 λ Environment at definition is frozen in closure… And is used to evaluate function body Explicit evaluation rule for recursion

17 λ dyn Lexical vs. Dynamic Scope 17 λ Bare lambdas, so all free variables resolved in calling environment

18 λ dyn Lexical vs. Dynamic Scope 18 λ No need for fix construct

19 Open Types for λ dyn 19 Types (Base or Arrow) Open Types Type Environments Open Type Environments

20 Open Types for λ dyn 20 Open Typing Open function type describes environment for function body

21 Open Types for λ dyn 21 Open Typing Open function type describes environment for function body Type environment at function definition is irrelevant

22 Open Types for λ dyn 22 Open Typing STLC + Fix In some sense, extreme generalization of [T-Fix]

23 Open Types for λ dyn 23 Open Typing STLC + Fix

24 Open Types for λ dyn 24 Open Typing For every Rely-set contains Guarantee-set contains (most recent, if multiple)

25 Open Types for λ dyn 25 Open Typing For every Rely-set contains Guarantee-set contains (most recent, if multiple) Discharge all assumptions

26 Open Types for λ dyn 26 Open Typing

27 Examples 27 let fact = λn. if n <= 1 then 1 else n * fact(n-1) in fact 5 fact :: (fact :: Int  Int)  Int  Int

28 Examples 28 let fact = λn. if n <= 1 then 1 else n * fact(n-1) in fact 5 GuaranteeRely fact :: (fact :: Int  Int)  Int  Int ✓

29 Error: var [tock] not found Examples 29 let tick n = if n > 0 then “tick ” ++ tock n else “” in tick 2;

30 Examples 30 let tick n = if n > 0 then “tick ” ++ tock n else “” in tick 2; tick :: (tock :: Int  Str)  Int  Str

31 Examples 31 let tick n = if n > 0 then “tick ” ++ tock n else “” in tick 2; GuaranteeRely tick :: (tock :: Int  Str)  Int  Str ✗

32 “tick tock tick tock ” Examples 32 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in tick 2;

33 Examples 33 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in tick 2; tick :: (tock :: Int  Str)  Int  Str tock :: (tick :: Int  Str)  Int  Str

34 Examples 34 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in tick 2; tick :: (tock :: Int  Str)  Int  Str tock :: (tick :: Int  Str)  Int  Str GuaranteeRely ✓

35 Error: “bad” not a function Examples 35 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in let tock = “bad” in tick 2;

36 Examples 36 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in let tock = “bad” in tick 2; tock :: Str tick :: (tock :: Int  Str)  Int  Str tock :: (tick :: Int  Str)  Int  Str

37 Examples 37 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in let tock = “bad” in tick 2; GuaranteeRely tock :: Str tick :: (tock :: Int  Str)  Int  Str tock :: (tick :: Int  Str)  Int  Str ✗

38 “tick tick ” Examples 38 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in let tock = tick (n-1) in tick 2;

39 Examples 39 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in let tock = tick (n-1) in tick 2; tick :: (tock :: Int  Str)  Int  Str tock :: (tick :: Int  Str)  Int  Str

40 Examples 40 let tick n = if n > 0 then “tick ” ++ tock n else “” in let tock n = “tock ” ++ tick (n-1) in let tock = tick (n-1) in tick 2; GuaranteeRely tick :: (tock :: Int  Str)  Int  Str tock :: (tick :: Int  Str)  Int  Str ✓

41 Recap 41 Open Types capture “late packaging” of recursive definitions in dynamically-scoped languages (Metatheory has not yet been worked) Several potential applications in lexically-scoped languages…

42 Open Types for λ ref 42 For open types in this setting, type system must support strong updates to mutable variables e.g. Thiemann et al. (ECOOP 2010), Chugh et al. (OOPSLA 2012) References in λ ref are similar to dynamically-scoped bindings in λ dyn

43 Open Types for λ ref 43 let tick = ref null in let tock = ref null in tick := λn. if n > 0 then “tick ” ++ !tock(n) else “”; tock := λn. “tock ” ++ !tick(n-1); !tick(2); tick :: (tock :: Ref (Int  Str))  Ref (Int  Str) tock :: (tick :: Ref (Int  Str))  Ref (Int  Str) tick :: Ref Null tock :: Ref Null tick :: (tock :: Ref (Int  Str))  Ref (Int  Str) tock :: Ref Null GuaranteeRely ✓ tick :: (tock :: Ref (Int  Str))  Ref (Int  Str) tock :: (tick :: Ref (Int  Str))  Ref (Int  Str)

44 Open Types for Methods 44 let tick n = if n > 0 then “tick ” ++ this.tock(n) else “” in let tock n = “tock ” ++ this.tick(n-1) in let obj = {tick=tick; tock=tock} in obj.tick(2); tick :: (this :: {tock: Int  Str})  Int  Str tock :: (this :: {tick: Int  Str})  Int  Str

45 Related Work Dynamic scope in lexical settings for: –Software updates –Dynamic code loading –Global flags Implicit Parameters of Lewis et al. (POPL 2000) –Open types mechanism resembles their approach –We aim to support recursion and references Other related work –Bierman et al. (ICFP 2003) –Dami (TCS 1998), Harper (Practical Foundations for PL) –…–… 45

46 Thanks! 46 Thoughts? Questions? Open Types for Checking Recursion in: 1.Dynamically-scoped λ-calculus 2.Lexically-scoped λ-calculus with references

47 EXTRA SLIDES 47

48 Higher-Order Functions 48 Disallows function arguments with free variables This restriction precludes “downwards funarg problem” To be less restrictive:

49 -17 Partial Environment Consistency 49 let negateInt () = 0 - x in let negateBool () = not x in let x = 17 in negateInt (); negateInt :: (x :: Int)  Unit  Int negateBool :: (x :: Bool)  Unit  Bool x :: Int Safe at run-time even though not all assumptions satisfied

50 Partial Environment Consistency 50 To be less restrictive: Only and its transitive dependencies in


Download ppt "A Fix for Dynamic Scope Ravi Chugh U. of California, San Diego."

Similar presentations


Ads by Google