SLIDE 1
A Semantics for Lazy Types
Bachelor Thesis
Georg Neis Advisor: Andreas Rossberg Programming Systems Lab Saarland University June 8, 2006
SLIDE 2 Motivation
◮ Open and distributed programming: dynamic loading and
linking
◮ Type checking at runtime ◮ Laziness
SLIDE 3 Motivation
◮ Open and distributed programming: dynamic loading and
linking
◮ Type checking at runtime ◮ Laziness
◮ Dynamic type checking: comparison of type expressions ◮ Reduction to normal-form ◮ Due to laziness: may interleave with term-level reduction!
SLIDE 4 Motivation
◮ Open and distributed programming: dynamic loading and
linking
◮ Type checking at runtime ◮ Laziness
◮ Dynamic type checking: comparison of type expressions ◮ Reduction to normal-form ◮ Due to laziness: may interleave with term-level reduction! ◮ Task: develop calculus (based on Fω) that models this
SLIDE 5
An example from Alice ML
(* A *) type t = int val x : t = 5 (* B *) import type t; val x : t from "A" type u = t val y : u*u = (x,x) (* C *) import type u = int; val y : u*u from "B" type v = int val z = #1 y
SLIDE 6
Lazy evaluation in Alice ML
◮ Provided by lazy futures ◮ Example: (fn f ⇒ f 1) (lazy (fn x ⇒ x) (fn n ⇒ n+41))
SLIDE 7
Modeling lazy evaluation in the untyped lambda calculus
◮ e ::= x | λx.e | e1 e2 | let x = e1 in e2 | lazy x = e1 in e2
SLIDE 8
Modeling lazy evaluation in the untyped lambda calculus
◮ e ::= x | λx.e | e1 e2 | let x = e1 in e2 | lazy x = e1 in e2 ◮ Translation of the previous example:
(fn f ⇒ f 1) (lazy (fn x ⇒ x) (fn n ⇒ n+41)) (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y)
SLIDE 9
Modeling lazy evaluation in the untyped lambda calculus
Reduction:
◮ (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y) −
→
SLIDE 10
Modeling lazy evaluation in the untyped lambda calculus
Reduction:
◮ (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y) −
→
◮ lazy y = (λx.x) (λn.n + 41) in (λf .f 1) y −
→
SLIDE 11
Modeling lazy evaluation in the untyped lambda calculus
Reduction:
◮ (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y) −
→
◮ lazy y = (λx.x) (λn.n + 41) in (λf .f 1) y −
→
◮ lazy y = (λx.x) (λn.n + 41) in y 1 −
→
SLIDE 12
Modeling lazy evaluation in the untyped lambda calculus
Reduction:
◮ (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y) −
→
◮ lazy y = (λx.x) (λn.n + 41) in (λf .f 1) y −
→
◮ lazy y = (λx.x) (λn.n + 41) in y 1 −
→
◮ let y = (λx.x) (λn.n + 41) in y 1 −
→
SLIDE 13
Modeling lazy evaluation in the untyped lambda calculus
Reduction:
◮ (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y) −
→
◮ lazy y = (λx.x) (λn.n + 41) in (λf .f 1) y −
→
◮ lazy y = (λx.x) (λn.n + 41) in y 1 −
→
◮ let y = (λx.x) (λn.n + 41) in y 1 −
→
◮ let y = (λn.n + 41) in y 1 −
→
SLIDE 14
Modeling lazy evaluation in the untyped lambda calculus
Reduction:
◮ (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y) −
→
◮ lazy y = (λx.x) (λn.n + 41) in (λf .f 1) y −
→
◮ lazy y = (λx.x) (λn.n + 41) in y 1 −
→
◮ let y = (λx.x) (λn.n + 41) in y 1 −
→
◮ let y = (λn.n + 41) in y 1 −
→
◮ (λn.n + 41) 1 −
→
SLIDE 15
Modeling lazy evaluation in the untyped lambda calculus
Reduction:
◮ (λf .f 1) (lazy y = (λx.x) (λn.n + 41) in y) −
→
◮ lazy y = (λx.x) (λn.n + 41) in (λf .f 1) y −
→
◮ lazy y = (λx.x) (λn.n + 41) in y 1 −
→
◮ let y = (λx.x) (λn.n + 41) in y 1 −
→
◮ let y = (λn.n + 41) in y 1 −
→
◮ (λn.n + 41) 1 −
→
◮ 1 + 41 −
→ 42
SLIDE 16
Modeling lazy evaluation in the untyped lambda calculus
Contexts:
◮ L ::=
| lazy x = e in L
◮ E ::=
| E e | v E | . . .
SLIDE 17
Modeling lazy evaluation in the untyped lambda calculus
Contexts:
◮ L ::=
| lazy x = e in L
◮ E ::=
| E e | v E | . . .
◮ Suspend:
LE[lazy x = e1 in e2] − → L[lazy x = e1 in E[e2]]
SLIDE 18
Modeling lazy evaluation in the untyped lambda calculus
Contexts:
◮ L ::=
| lazy x = e in L
◮ E ::=
| E e | v E | . . .
◮ Suspend:
LE[lazy x = e1 in e2] − → L[lazy x = e1 in E[e2]]
◮ Trigger1:
L1[lazy x = e1 in L2E[x v]] − → L1[let x = e1 in L2E[x v]]
SLIDE 19
Existential types
◮ To model a simple form of modules ◮ Example:
structure S = struct type t = bool val n = 42 end : sig type t val n : int end bool, 42:∃α.int
SLIDE 20
Existential types
◮ Accessing a module: let α, x = e1 in e2
SLIDE 21
Existential types
◮ Accessing a module: let α, x = e1 in e2 ◮ Reduction:
LE[let α, x = τ, v:τ ′ in e] − → LE[e[α := τ][x := v]]
SLIDE 22
Existential types
◮ Accessing a module: let α, x = e1 in e2 ◮ Reduction:
LE[let α, x = τ, v:τ ′ in e] − → LE[e[α := τ][x := v]]
◮ Lazy variant for loading a module: lazy α, x = e1 in e2
SLIDE 23
Typecase
◮ Comparison of two types τ1 and τ2 ◮ tcase e:τ1 of x:τ2 then e1 else e2
SLIDE 24 Typecase
◮ Comparison of two types τ1 and τ2 ◮ tcase e:τ1 of x:τ2 then e1 else e2 ◮ Reduction:
◮ LE[tcase v:ν of x:ν then e1 else e2] −
→ LE[e1[x := e]]
◮ LE[tcase v:ν of x:ν′ then e1 else e2] −
→ LE[e2] (ν = ν′)
SLIDE 25
Lazy types
◮ Consider: lazy α, x = e in tcase x:α of y:int then y else 0 ◮ α ?
= int
SLIDE 26
Lazy types
◮ Consider: lazy α, x = e in tcase x:α of y:int then y else 0 ◮ α ?
= int
◮ lazy α, x = e in tcase x:α of y:int then y else 0 −
→ let α, x = e in tcase x:α of y:int then y else 0
SLIDE 27
Lazy types
◮ Consider: lazy α, x = e in tcase x:α of y:int then y else 0 ◮ α ?
= int
◮ lazy α, x = e in tcase x:α of y:int then y else 0 −
→ let α, x = e in tcase x:α of y:int then y else 0
◮ Trigger2:
L1[lazy α, x = e in L2ET[α]] − → L1[let α, x = e in L2ET[α]]
SLIDE 28
An example from Alice ML
(* A *) type t = int val x : t = 5 (* B *) import type t; val x : t from "A" type u = t val y : u*u = (x,x) (* C *) import type u = int; val y : u*u from "B" type v = int val z = #1 y
SLIDE 29 Translation into the calculus
(* A *) type t = int val x : t = 5
= λ :1. int, 5:∃α.α
SLIDE 30 Translation into the calculus
(* B *) import type t; val x : t from "A" type u = t val y : u*u = (x,x)
= λ :1. lazy t, x = a () in t, x, x:∃α.α×α
SLIDE 31 Translation into the calculus
(* C *) import type u = int; val y : u*u from "B" type v = int val z = #1 y
= λ :1. lazy , y = let u, y = b () in tcase y : u×u of y′ : int×int then int, y′:∃α.int×int else ⊥ in int, fst y:∃α.int
SLIDE 32
Design Space
◮ Three ways of type-level reduction – different degrees of
laziness
◮ Consider: int×((λβ.ν) α) ?
= bool×int (where α lazy)
SLIDE 33 Design Space
◮ Three ways of type-level reduction – different degrees of
laziness
◮ Consider: int×((λβ.ν) α) ?
= bool×int (where α lazy)
- 1. Naive: use the trigger rule
SLIDE 34 Design Space
◮ Three ways of type-level reduction – different degrees of
laziness
◮ Consider: int×((λβ.ν) α) ?
= bool×int (where α lazy)
- 1. Naive: use the trigger rule
- 2. Clever: perform the application
SLIDE 35 Design Space
◮ Three ways of type-level reduction – different degrees of
laziness
◮ Consider: int×((λβ.ν) α) ?
= bool×int (where α lazy)
- 1. Naive: use the trigger rule
- 2. Clever: perform the application
- 3. Smart: weak-head reduction
SLIDE 36 References
◮ Mart´
ın Abadi, Luca Cardelli, Benjamin Pierce, and Didier R´
- emy. Dynamic typing in polymorphic languages. Journal of
Functional Programming, January 1995.
◮ John Maraist, Martin Odersky, and Philip Wadler. A
call-by-need lambda calculus. Journal of Functional Programming, May 1998.
◮ Benjamin Pierce. Types and Programming Languages. The
MIT Press, February 2002.
◮ Zena Ariola and Matthias Felleisen. The call-by-need lambda
- calculus. Journal of Functional Programming, 1997.
◮ Matthias Berg. Polymorphic lambda calculus with dynamic
types, FoPra Thesis, October 2004. http://www.ps.uni-sb.de/∼berg/fopra.html
◮ Andreas Rossberg, Didier Le Botlan, Guido Tack, Thorsten
Brunklaus, and Gert Smolka. Alice through the looking glass. Trends in Functional Programming, volume 5, Intellect, 2005