1 Space-Efficient Gradual Typing David Herman Northeastern University Aaron Tomb, Cormac Flanagan...

Preview:

Citation preview

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 you.dherman@ccs.neu.edu

Recommended