Implementing a Dependently Typed λ -Calculus Ali Assaf Abbie Desrosiers Alexandre Tomberg.
-
Upload
nancy-julia-holt -
Category
Documents
-
view
228 -
download
0
Transcript of Implementing a Dependently Typed λ -Calculus Ali Assaf Abbie Desrosiers Alexandre Tomberg.
Implementing a Implementing a Dependently Typed Dependently Typed λλ--CalculusCalculus
Ali Assaf Abbie DesrosiersAlexandre Tomberg
OutlineOutlineλ-calculus.Implementation strategiesTyped λ-calculusPolymorphic types, System FDependent typesCurrent work
MotivationsMotivationsλ-calculus expresses function
abstractions◦Powerful, Turing-complete.◦Foundation of functional programming
languages.◦Strong connection with logic.
This project:◦Study types◦Explore different implementations
The The λλ-calculus-calculusVery simple language:
◦Terms M = x | λ x . M | M N◦Reductions (λ x . M) N => [N/x] M
Examples◦ Identity: λ x . x ◦Constant function: λ x . λ y . x◦Omega: λ x . (x x)
Implementation strategiesImplementation strategiesExplicit substitution
◦term = var “x” | lam “x” M | app M N◦“Natural way” of representing
lambda expressions.◦Problems :
No immediate α-renaming Free variable capture problem
Implementation strategies Implementation strategies (cont’d)(cont’d)De Bruijn indices
◦term M = Var n | lam M | app M N◦e.g. Identity: λ . 1, Constant: λ . λ . 2◦Advantages:
Unique representation
◦Problems: Not simple to manipulate.
λ x . (λ y . x) x = λ . (λ . 2). 1 Need to shift indices in substitution to avoid
capture.
Implementation strategies Implementation strategies (cont’d)(cont’d)Higher Order Abstract Syntax
(HOAS)◦Use the features of the meta-
language !◦term M = lam f | app M N
where f is a function term → term◦Term substitution :
sub (lam f) N => lam (f N)◦α-renaming already provided!◦WARNING : Leads to ridiculously short
implementations.
Our implementationsOur implementations
De Bruijn in SMLdatatype exp = var of int | lam of exp | app of exp * exp
fun shift (var x) l b = if x > b then var (x + l) else var x
| shift (lam m) l b = lam (shift m l (b + 1))
| shift (app (m, n)) l b = app(shift m l b, shift n l b)
fun sub (var y) s x l =
if y = x then shift s l 0 (* Substitution *)
else if y > x then var (y-1) (* Free variable *)
else var y (* Bound variable *)
| sub (lam m) s x l = lam (sub m s (x + 1) (l + 1))
| sub (app (m, n)) s x l = app (sub m s x l, sub n s x l)
fun eval (var x) = var x
| eval (lam m) = lam (eval m)
| eval (app (m, n)) = case eval m of
lam m' => eval (sub m' n 1 0)
| m' => (app (m', eval n))
HOAS in SMLdatatype exp = lam of (exp -> exp) | app of exp * exp;
fun eval (lam m) = lam (fn x => eval (m x))
| eval (app (m, n)) =
case eval m of
lam m' => eval (m' n)
| m' => app (m', n)
Our implementationsOur implementations
Twelfexp : type.
lam : (exp -> exp) -> exp.
app : exp -> exp -> exp.
eval : exp -> exp -> type.
eval/lam : eval (lam M) (lam M).
eval/app : eval (app M N) N'
<- eval M (lam M')
<- eval (M' N) N'.
SMLdatatype exp = lam of (exp -> exp)
| app of exp * exp;
fun eval (lam m) = lam (fn x => eval (m x))
| eval (app (m, n)) =
case eval m of
lam m' => eval (m' n)
| m' => app (m', n)
The The ωω problem problemConsider the function:
ω = λ x . ( x x )What happens if we apply it to itself?ω ω = (λ x . ( x x )) ω => ω ω => ω ω => ...Evaluation never terminates!
We say (ω ω) doesn’t have a normal form.
To solve this problem, we introduce types.
TypesTypesEach function f has a fixed
domain A and co-domain B (like sets in math).
types τ = a | τ → σwhere a is a base type (e.g. nat)
Typing rules
◦XXXXXXXXXXXXXX
Return of the Return of the ωωWhat happens to ω ?
◦ω = λ x. xxω : α → βx : α, but also x : α → βα ≠ α → β
ω cannot have a valid type!Simply-typed lambda calculus is strongly
normalizing.
Implementing typesImplementing typesMuch easier in Twelf: use HOAS.
This corresponds to Curry style.
t : type.a : t.arrow : t -> t -> t.%infix right 10 arrow.
exp : type.lam : (exp -> exp) -> exp.app : exp -> exp -> exp.
check : exp -> t -> type.check/lam : check (lam M) (A arrow B) <- {x:exp} (check x A -> check (M x) B).check/app : check (app M N) B <- check M (A arrow B) <- check N A.
ExamplesExamplesType checking:
◦ check (lam ([x] x)) (A arrow A)
Secret weapon: we can use Twelf to do type inference !◦ %query 1 * check (lam ([x] x)) T
T = X1 arrow X2 arrow X1.
ω ?◦ %query 1 * check (lam ([x] app x x)) T
Query error -- wrong number of solutions: expected 1 in * tries, but found 0
Another implementationAnother implementationCute trick :
Then ill-typed terms cannot even be constructed !
This corresponds to Church style.
t : type.a : t.arrow : t -> t -> t.%infix right 10 arrow.
exp : t -> type.lam : (exp T1 -> exp T2) -> exp (T1 arrow T2).app : exp (T1 arrow T2) -> exp T1 -> exp T2.
Limitations of simple Limitations of simple typestypesDecidable, but no longer Turing
complete.id = λ x : a . x
id = λ x : b . xid = λ x : nat . xid = λ x : (a → a) . x
We need to write a different identity function for each type.◦To avoid that we need polymorphism.
Polymorphism: System FPolymorphism: System FIdea: Allow abstraction over types.Then, we can write a single
identity function for any type a:Λ a . λ x : a . x
We extend our definition of types and terms:◦τ = a | τ → τ | Π a . τ◦M = x | λ x : τ . M | M N | Λ a . M | M {τ}
Implementations follow the same idea.
Dependent types : LFDependent types : LFIdea: Let types depend on values.Keep information about our types.Examples:
◦Vector : Nat → type.◦Vector n is the type of vectors of length
n.◦Exp t
Advantages:◦We won’t need to prove properties
about our programs !
Current workCurrent workPolymorphic types in TwelfDependent types in TwelfTypes in SML
◦Problems with HOAS.
Problems with HOASProblems with HOASCurrent functional languages (like
SML) present a few problems:◦Do not allow us to look inside functions.◦Hard to generate λ terms.
Solutions:◦ Improve functional programming languages.
Beluga
◦Try different paradigms. Python
Why Python?Why Python?Dynamically typed.Very flexible code generation.User-friendly interface.
I = Lam(lambda x : x)K = Lam(lambda x : Lam (lambda y : x))O = Lam(lambda x : App(x, x))print "I = ", Iprint "K = ", Kprint "O = ", O
>>> I = Lam u. (u)K = Lam w. (Lam v. (w))O = Lam y. ((y)(y))
Conclusions and future Conclusions and future workwork
Many type systems.Various
implementations. Besides
implementing, our goals include:◦ Proving equivalence of
representations.