Ravi Chugh U of California San Diego Backstory 2 Goal Types for Dynamic Languages Core λ Calculus Extensions Syntax and Semantics of JavaScript Translation à la Guha et al ID: 540587
Download Presentation The PPT/PDF document "A Fix for Dynamic Scope" is the property of its rightful owner. Permission is granted to download and print the materials on this web site for personal, non-commercial use only, and to display it on your personal computer provided you do not modify the materials and that you retain all copyright notices contained in the materials. By downloading content from our website, you accept the terms of this agreement.
Slide1
A Fix for Dynamic Scope
Ravi Chugh
U. of California, San DiegoSlide2
Backstory
2
Goal: Types for “Dynamic” Languages
Core
λ
-Calculus
+ Extensions
Syntax and Semantics
of JavaScript
Translation à la Guha et al.
(ECOOP 2010)Slide3
Backstory
3
Goal: Types for “Dynamic” Languages
Core
λ
-Calculus
+ Extensions
Approach: Type Check Desugared Programs
Simple
Imperative
,
RecursiveFunctions are Difficult to VerifySlide4
4
Translate to statically typed calculus?
var
fact
=
function
(n
)
{ if
(n <=
1)
{
return
1
;
}
else {
return
n * fact(n-1); }};Slide5
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…
✗Slide6
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); }
};
✗Slide7
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)
; }
};
✗Slide8
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)8Translate to statically typed calculus?
var
fact = function(n
)
{
if (n <= 1) { return 1; } else { return n * fact(n
-1)
;
}};
✓Slide9
let
fact
=
ref
(
λ
n. if n
<= 1 then
1 else n *
!fact(
n
-
1
)
)
9Slide10
10
let
fact
=
ref
(
λn. 0) in
fact
:= λn
. if n
<= 1
then
1
else
n
*
!fact
(
n
-
1
)
;Backpatching Pattern in λreffact :: Ref (Int Int)
Assignment
relies on
and
guarantees
the reference invariantSlide11
11
let
fact = ref
(
λ
n
. 0) infact :=
λ
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 isinitialized with dummy function…Slide12
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 functionSlide13
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 functionType system must checkassumptions at every dereferenceSlide14
Proposal: Open Types
for
λ
ref14
let
fact = ref (λn
.
if n
<= 1 then
1 else
n
*
!fact
(
n
-
1
)
)
Motivated by
λ
ref programs that result fromdesugaring JavaScript programs Slide15
Proposal: Open Types
for
λ
ref15
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 Slide16
Lexical
vs.
Dynamic
Scope
16
λ
Environment at definition is frozen in closure…
And is used to evaluate function body
Explicit evaluation rule for recursionSlide17
λ
dyn
Lexical
vs.
Dynamic
Scope
17
λ
Bare lambdas, so
all
free variables resolved in calling environmentSlide18
λ
dyn
Lexical
vs.
Dynamic
Scope
18
λ
No need for
fix constructSlide19
Open Types for
λ
dyn
19
Types (Base or Arrow)
Open Types
Type Environments
Open Type EnvironmentsSlide20
Open Types for
λ
dyn
20
Open Typing
Open function type describes environment for function bodySlide21
Open Types for
λ
dyn
21
Open Typing
Open function type describes environment for function body
Type environment at function definition is
irrelevantSlide22
Open Types for
λ
dyn
22
Open Typing
STLC + Fix
In some sense, extreme generalization of [T-Fix]Slide23
Open Types for
λ
dyn
23
Open Typing
STLC + FixSlide24
Open Types
for
λ
dyn
24
Open Typing
For every
Rely-set
contains
Guarantee-set
contains
(most recent, if multiple)Slide25
Open Types for
λ
dyn
25
Open Typing
Open Typing
For every
Rely-set
contains
Guarantee-set
contains
(most recent, if multiple)
Discharge all assumptionsSlide26
Open Types for
λ
dyn
26
Open TypingSlide27
Examples
27
let
fact
=
λn. if
n
<= 1
then 1 else
n *
fact
(
n
-
1
)
in
fact 5
fact
:: (
fact
:: Int Int) Int Int Slide28
Examples
28
let
fact =
λ
n
.
if
n <= 1 then 1
else n * fact(
n-
1)
in
fact 5
Guarantee
Rely
fact
:: (
fact
:: Int
Int
)
Int
Int
✓Slide29
Error: var [tock] not found
Examples
29
let
tick n
=
if
n
>
0
then
“tick ”
++
tock n
else
“”
in
tick 2
;Slide30
Examples
30
let
tick n
=
if n >
0
then “tick ” ++
tock n else
“” in
tick 2
;
tick
:: (
tock
:: Int
Str
)
Int Str Slide31
Examples
31
let
tick n =
if
n > 0 then “tick ” ++ tock n else “” in
tick 2
;
Guarantee
Rely
tick
:: (
tock
:: Int
Str
)
Int
Str ✗Slide32
“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) intick 2
;Slide33
Examples
33
let
tick n
=
if n >
0
then “tick ” ++
tock n else
“” in
let
tock n
=
“tock ”
++
tick
(
n
-
1
) intick 2;tick :: (tock :: Int Str) Int
Str
tock
:: (
tick :: Int Str) Int Str Slide34
Examples
34
let
tick n =
if
n > 0 then “tick ” ++ tock n else “” in
let tock n =
“tock ” ++ tick (
n-1) intick 2
;
tick
:: (
tock
:: Int
Str
)
Int
Str
tock
:: (
tick
:: Int
Str) Int Str GuaranteeRely✓Slide35
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) inlet
tock
=
“bad”
in
tick 2;Slide36
Examples
36
let
tick n
=
if n >
0
then “tick ” ++
tock n else
“” in
let
tock n
=
“tock ”
++
tick
(
n
-
1
) inlet tock = “bad” in tick 2;
tock
::
Str
tick :: (tock :: Int Str) Int Str tock :: (tick :: Int
Str)
Int Str Slide37
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
;
Guarantee
Rely
tock
::
Str
tick
:: (
tock
:: Int
Str) Int Str tock :: (tick :: Int Str)
Int
Str ✗Slide38
“tick tick ”
Examples
38
let
tick n
=
if
n
>
0
then
“tick ”
++
tock n
else
“”
in
let
tock n
= “tock ” ++ tick (n-1) inlet
tock
=
tick
(
n
-1) in tick 2;Slide39
Examples
39
let
tick n
=
if n >
0
then “tick ” ++
tock n else
“” in
let
tock n
=
“tock ”
++
tick
(
n
-
1
) inlet tock = tick (n-1) in
tick 2
;
tick
:: (
tock
:: Int Str) Int Str tock :: (tick :: Int Str)
Int
Str
tock :: (tick :: Int
Str
)
Int
Str
Slide40
Examples
40
let
tick n =
if
n > 0 then “tick ” ++ tock n else “” in
let tock n =
“tock ” ++ tick (
n-1) inlet tock =
tick (
n
-
1) in
tick 2
;
Guarantee
Rely
tick
:: (
tock
:: Int
Str
)
Int Str tock :: (tick :: Int Str)
Int
Str ✓
tock
:: (
tick
:: Int
Str
)
Int
Str
Slide41
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…Slide42
Open Types for λ
ref
42
For open types in this setting,
type system must support
strong updates
to mutable variablese.g. Thiemann et al. (ECOOP 2010), Chugh et al. (OOPSLA 2012)References
in
λref are similar to
dynamically-scoped bindings in λdynSlide43
Open Types for λ
ref
43
let
tick =
ref null inlet tock
=
ref null intick
:= λ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
tick
:: Ref Null
tock
:: Ref Null
tick
:: (
tock
:: Ref (Int
Str
))
Ref (Int
Str
)
tock
:: Ref Null
Guarantee
Rely
✓
tick
:: (
tock
:: Ref (Int
Str
))
Ref (Int
Str
)
tock
:: (
tick
:: Ref (Int
Str
))
Ref (Int
Str
)
Slide44
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) inlet obj = {tick=tick
;
tock
=
tock
} in
obj.tick(2);tick :: (this :: {tock: Int Str}) Int
Str
tock
:: (this
:: {tick: Int
Str
}
)
Int
Str
Slide45
Related Work
Dynamic scope in lexical settings for:
Software updates
Dynamic code loading
Global flagsImplicit Parameters of Lewis et al. (POPL 2000)Open types mechanism resembles their approachWe aim to support recursion and referencesOther related work
Bierman et al. (ICFP 2003)Dami (TCS 1998), Harper (Practical Foundations for PL)
…45Slide46
Thanks!
46
Thoughts? Questions?
Open Types for Checking Recursion in
:
Dynamically-scoped
λ-calculus
Lexically-scoped λ-calculus with referencesSlide47
EXTRA SLIDES
47Slide48
Higher-Order Functions
48
Disallows function arguments with free variables
This restriction precludes “downwards funarg problem”
To be less restrictive:Slide49
-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 satisfiedSlide50
Partial Environment Consistency
50
To be less restrictive:
Only and
its transitive
dependencies in