space-efficient gradual typing
DESCRIPTION
Space-Efficient Gradual Typing. David Herman Northeastern University Aaron Tomb, Cormac Flanagan University of California, Santa Cruz. The point. Naïve type conversions in functional programming languages are not safe for space. But they can and should be. Gradual Typing: - PowerPoint PPT PresentationTRANSCRIPT
1
Space-Efficient Gradual Typing
David HermanNortheastern University
Aaron Tomb, Cormac FlanaganUniversity of California, Santa Cruz
2
The point
Naïve type conversions in functional programming languages are not safe for space.
But they can and should be.
3
Gradual Typing:
Software evolution via hybrid type checking
4
Dynamic vs. static typing
DynamicTyping
StaticTyping
5
Gradual typing
DynamicTyping
StaticTyping
6
Type checking
let x = f() in … let y : Int = x - 3 in …
7
Type checking
let x : ? = f() in … let y : Int = x - 3 in …
8
Type checking
let x : ? = f() in … let y : Int = x - 3 in …
- : Int × Int → Int
9
Type checking
let x : ? = f() in … let y : Int = <Int>x - 3 in …
10
Type checking
let x : ? = f() in … let y : Int = <Int>x - 3 in …
Int
11
Evaluation
let x : ? = f() in … let y : Int = <Int>x - 3 in …
12
Evaluation
let x : ? = 45 in … let y : Int = <Int>x - 3 in …
13
Evaluation
let y : Int = <Int>45 - 3 in …
14
Evaluation
let y : Int = 45 - 3 in …
15
Evaluation
let y : Int = 42 in …
16
Evaluation (take 2)
let x : ? = f() in … let y : Int = <Int>x - 3 in …
17
Evaluation (take 2)
let x : ? = true in … let y : Int = <Int>x - 3 in …
18
Evaluation (take 2)
let y : Int = <Int>true - 3 in …
19
Evaluation (take 2)
error: “true is not an Int”
20
Static semantics (Siek & Taha)
Type compatibility
E ⊢ e1 : (S→T) E ⊢ e2 : S′ S′ ~: S
E ⊢ (e1 e2) : T
21
Static semantics (Siek & Taha)
Type compatibility
E ⊢ e1 : (S→T) E ⊢ e2 : S′ S′ ~: S
E ⊢ (e1 e2) : T
22
Static semantics (Siek & Taha)
Type compatibility ≠ subtyping!
T ~: T T ~: ? ? ~: T
T1 ~: S1 S2 ~: T2
(S1→S2) ~: (T1→T2)
23
Static semantics (Siek & Taha)
Cast insertion
E ⊢ e1 ↪ t1 : (S→T) E ⊢ e2 ↪ t2 : S′ S′ ~: S
E ⊢ (e1 e2) ↪ (t1 (<S> t2)) : T
E ⊢ e ↪ t : T
cast argument expression
24
Space Leaks
25
Space leaks
fun even(n) = if (n = 0) then true else odd(n - 1)
fun odd(n) = if (n = 0) then false else even(n - 1)
26
Space leaks
fun even(n : Int) = if (n = 0) then true else odd(n - 1)
fun odd(n : Int) : Bool = if (n = 0) then false else even(n - 1)
27
Space leaks
fun even(n : Int) = if (n = 0) then true else odd(n - 1)
fun odd(n : Int) : Bool = if (n = 0) then false else <Bool>even(n - 1)
28
Space leaks
fun even(n : Int) = if (n = 0) then true else odd(n - 1)
fun odd(n : Int) : Bool = if (n = 0) then false else <Bool>even(n - 1)
non-tail call!
29
Space leaks
even(n)→* odd(n - 1)→* <Bool>even(n - 2)→* <Bool>odd(n - 3)→* <Bool><Bool>even(n - 4)→* <Bool><Bool>odd(n - 5)→* <Bool><Bool><Bool>even(n - 6)→* …
30
Naïve Function Casts
31
Casts in functional languages<Int>n → n<Int>v → error: “v not an Int” (if v∉Int)
<σ→τ>λx:?.e → …
32
Casts in functional languages<Int>n → n<Int>v → error: “v not an Int” (if v∉Int)
<σ→τ>λx:?.e → λz:σ.<τ>((λx:?.e) z)
Very useful, very popular… unsafe for space.
fresh, typed proxy
cast result
33
More space leaks
fun evenk(n : Int, k : ? → ?) = if (n = 0) then k(true) else oddk(n – 1, k)
fun oddk(n : Int, k : Bool → Bool) = if (n = 0) then k(false) else evenk(n – 1, k)
34
More space leaks
fun evenk(n : Int, k : ? → ?) = if (n = 0) then k(true) else oddk(n – 1, <Bool→Bool>k)
fun oddk(n : Int, k : Bool → Bool) = if (n = 0) then k(false) else evenk(n – 1, <?→?>k)
35
More space leaks
evenk(n, k0)
→* oddk(n - 1, <Bool→Bool>k0)
→* oddk(n - 1, λz:Bool.<Bool>k0(z))→* evenk(n - 2, <?→?>λz:Bool.<Bool>k0(z))
→* evenk(n - 2, λy:?.(λz:Bool.<Bool>k0(z))(y))→* oddk(n - 3, <Bool→Bool>λy:?.(λz:Bool.<Bool>k0(z))(y))
→* oddk(n – 3, λx:Bool.(λy:?.(λz:Bool.<Bool>k0(z))(y))(x))
→* evenk(n - 4, <?→?>λx:Bool.(λy:?.(λz:Bool.<Bool>k0(z))(y))(x))
→* evenk(n - 4, λw:?.(λx:Bool.(λy:?.(λz:Bool.<Bool>k0(z))(y))(x))(w))→* oddk(n - 5, <Bool→Bool>λw:?.(λx:Bool.(λy:?.(λz:Bool.<Bool>k0(z))(y))(x))(w))
→* oddk(n - 5, λv:Bool.<Bool>(λw:?.(λx:Bool.(λy:?.(λz:Bool.<Bool>k0(z))(y))(x))(w))(v))
→* …
(…without even using k0!)
36
Space-Efficient Gradual Typing
37
Intuition
Casts are like function restrictions(Findler and Blume, 2006)
Can their representation exploit the properties of restrictions?
38
Exploiting algebraic properties
Closure under composition:
<Bool>(<Bool> v) = (<Bool>◦<Bool>) v
39
Exploiting algebraic properties
Idempotence:
<Bool>(<Bool> v) = (<Bool>◦<Bool>) v
= <Bool> v
40
Exploiting algebraic properties
Distributivity:
(<?→?>◦<Bool→Bool>) v = <(Bool◦?)→(?◦Bool)> v
41
Space-efficient gradual typing Generalize casts to coercions
(Henglein, 1994) Change representation of casts
from <τ> to <c> Merge casts at runtime:
<c>(<d> e) → <c◦d>e
merged before evaluating e
This coercion can be
simplified!
42
Space-efficient gradual typing Generalize casts to coercions
(Henglein, 1994) Change representation of casts
from <τ> to <c> Merge casts at runtime:
<c>(<d> e) → <c◦d>e
→ <c′>e
43
Static semantics
Type compatibility
E ⊢ e1 : (S→T) E ⊢ e2 : S′ S′ ~: S
E ⊢ (e1 e2) : T
44
Static semantics
Type compatibility
T ~: T T ~: ? ? ~: T
T1 ~: S1 S2 ~: T2
(S1→S2) ~: (T1→T2)
45
Static semantics
Cast insertion
E ⊢ e1 ↪ t1 : (S→T) E ⊢ e2 ↪ t2 : S′ c=coerce(S′, S)
E ⊢ (e1 e2) ↪ (t1 (<c> t2)) : T
E ⊢ e ↪ t : T
computes a type
coercionreplaces the
type cast with a coercion
46
Henglein’s coercions
c ::= Succ | Fail | D! | D? | Fun c c | c◦cD ::= Int | Bool | Fun
coerce(T, T) = Succcoerce(Int, ?) = Int!coerce(?, Int) = Int?
47
Henglein’s coercions
c ::= Succ | Fail | D! | D? | Fun c c | c◦cD ::= Int | Bool | Fun
coerce(S1→S2, T1→T2) =Fun coerce(T1, S1) coerce(S2, T2)
coerce(?, T1→T2) =coerce(?→?, T1→T2)◦Fun?
coerce(T1→T2, ?) =Fun!◦coerce(T1→T2, ?→?)
48
Coercion normalization
c◦Succ = cSucc◦c = c
c◦Fail = FailFail◦c = Fail
D?◦D! = SuccInt?◦Bool! = Fail
(Fun d1 d2)◦(Fun c1 c2) = Fun (c1◦d1) (d2◦c2)
49
Dynamic semantics
v ::= u | <c> uu ::= n | b | λx:S.t
50
Dynamic semantics
E ::= [] | (E t) | (v E) | <c> PP ::= [] | (E t) | (v E)
E[<c> (<d> t)] → E[<c◦d> t]E[(λx:S.t) v] → E[t[v/x]]E[(<Fun c d> u) v] → E[<d> (u (<c> v))]E[<Succ> u] → E[u]
(if E ≠ E′[<c> []])E[<Fail> u] → error
(if E ≠ E′[<c> []])
51
Tail recursion
even(n)→* odd(n - 1)→* <Bool>even(n - 2)→* <Bool>odd(n - 3)→* <Bool><Bool>even(n - 4)→* <Bool>even(n - 4)→* <Bool>odd(n - 5)→* <Bool><Bool>even(n - 6)→* <Bool>even(n - 6)→* …
52
Bounded proxies
evenk(n, k0)
→* oddk(n - 1, <Bool→Bool>k0)
→* evenk(n - 2, <?→?><Bool→Bool>k0)
→* evenk(n - 2, <Bool→Bool>k0)
→* oddk(n - 3, <Bool→Bool>k0)
→* evenk(n - 4, <?→?><Bool→Bool>k0)
→* evenk(n - 4, <Bool→Bool>k0)
→* oddk(n - 5, <Bool→Bool>k0)→* …
53
Guaranteed.
Theorem: any program state S during evaluation of a program P is bounded by
kP · sizeOR(S)
sizeOR(S) = size of S without any casts
54
Earlier error detection
<Int→Int>(<Bool→Bool> e)
→ <Fail→Fail> e
→ error: “Int→Int ≠ Bool→Bool”
55
Earlier error detection
E ::= [] | (E t) | (v E) | <c> PP ::= [] | (E t) | (v E)
E[<c> (<d> t)] → E[<c◦d> t]E[(λx:S.t) v] → E[t[v/x]]E[(<Fun c d> u) v] → E[<d> (u (<c> v))]E[<Succ> u] → E[u]
(if E ≠ E′[<c> []])E[<Fail> t] → error
(if E ≠ E′[<c> []])
why bother evaluating t?
56
Implementation
57
Coercions as continuation marks
E [<?→?><Bool→Bool> e]
E
58
Coercions as continuation marks
E [<?→?><Bool→Bool> e]
E
?→?
59
Coercions as continuation marks
E [<Bool→Bool> e]
E
?→?
60
Coercions as continuation marks
E [<Bool→Bool> e]
E
Bool→Bool
61
Coercions as continuation marks
E [e]
E
Bool→Bool
62
Alternative approaches
Coercion-passing style
λ(x,c).f(x,simplify(c◦d))
Trampoline
λ(x).(d,λ().f(x))
63
Parting Thoughts
64
Related work
Gradual typing Siek and Taha (2006, 2007)
Function proxies Findler and Felleisen (1998, 2006): Software contracts Gronski, Knowles, Tomb, Freund, Flanagan (2006):
Hybrid typing, Sage Tobin-Hochstadt and Felleisen (2006):
Interlanguage migration Coercions
Henglein (1994): Dynamic typing Space efficiency
Clinger (1998): Proper tail recursion Clements (2004): Security-passing style
65
Contributions
Space-safe representation and semantics of casts for functional languages
Supports function casts and tail recursion Earlier error detection Proof of space efficiency Three implementation strategies
66
The point, again
Naïve type conversions in functional programming languages are not safe for space.
But they can and should be.
Thank [email protected]