♥ Dependenent Types in Practicle programming
♥ Thanks Giving
Lesly Lamport
"Unfortunately one often pays a price for [languages which impose no discipline of types] in the time taken to find rather inscrutable bugs, anyone who mistakenly applies CDR to an atom in LISP & finds himself absurdly adding a property list to an integer, will know the symptoms ". – Robin Milner
Some Advantages of Types :
1. Detecting program errors at compile-time.
2. Enabling compiler optimizations.
3. Facilitating program verification :
▹ Using types to encode program properties
▹ Verifying the encoded properties via type-checking
4. Serving as program documentation.
♥ ML {metalanguage}
▹ Developed by Robin Milner and others in
the early '70s @University of Edinburgh
▹ Well-designed type system.
▹ Hindley–Milner type system :
Type inference algo can automatically
assign the types of most expressions
without requiring explicit type annotations.
Our Favorite ML Program
append : 'alist-> 'alist-> 'alist
fun append (nil, l2) = l2
| append (x::xs, l2) = x::append(xs, l2);
Type Systems:
♥ Rich , Realistic Languages * Simple Type system *
SML , OCaml, Haskell
^ Type Checking is Decidable.
♥ Small , Pure Languages * Richer Type theories *
Those underlying Coq, NuPrl , PX
^ Type checking is generally Undecidable
or requires extensive verbose annotations.
Shortcomings of Realistic Languages.
Only relatively elementary properties of program
can be expressed and thus checked by a type checker.
Eg : The error of taking the first element
out of an empty list can not be prevented
by ML type system.
TradeOff : "Expressibility Vs Decidability"
Or write extensive verbose annotations.
♥ Goal :
" Designing a type system for practical programming
in which a restricted form of dependent types is
available, allowing more program invariants to be
captured by types".
Conservatively extend the type system of ML
by allowing some dependencies while maintaining
practical & unintrusive type-checking.
♥ Overview of Paper
Enriching the type system of ML with a restricted
form of dependent types, where type index objects
are drawn from a constraint domain C, leading to
the DML(C) language schema.
▹ More Precise Type information.
▹ Facilitates Program error detection.
▹ Complier Optimisation.
Start Point ML0
base types d ::= int | bool | (user defined datatypes)
types t ::= d | t1 -> t2 | t1 * t2
patterns p ::= x | c(p) | <> |
match clauses ms ::= (p => e) | (p => e | ms)
expressions
e ::= x | f | c | if (e, e1, e2) | <> | |
lam x:t. e | fix f:t. e | e1(e2) |
let x=e1 in e2 end | case e of ms
values v ::= x | c | | lam x:t. e
context Γ ::= . | Γ, x: t
Dependent Types :
Dependent types are "types that depend on elements
of other types".
Example :
▹ Type An of vectors of length n with components of type A
Type An depends on the number n, or that
An is a "family of types indexed by the number n".
▹ Type Am × n of m × n-matrices.
▹ Type of trees of a certain height.
▹ x:Nat, y:Seq(x) |- ...
• Our Favorite ML function Is back :
Our Favorite ML function :
append: ’alist -> ’alist -> ’alist
A correct implementation of the append function on lists
sld return a list of length m + n when given two lists
of length m and n. This property cannot be captured by
the type system of ML(above type).
• Reason abt list lengths with restricted form of dep types
append : ’alist(m) -> ’alist(n) -> ’alist(m + n)
m,n are index objects
Full Example :
datatype ’a list = nil | cons of ’a * ’a list
typeref ’a list of nat with
(* indexing the datatype ’a list with nat *)
nil <| ’a list(0)
| cons <| {n:nat} ’a * ’a list(n) -> ’a list(n+1)
fun(’a)
append(nil, ys) = ys
| append(cons(x, xs), ys) = cons(x, append(xs, ys))
where append <| {m:nat}{n:nat} ’a list(m) * ’a list(n)
-> ’a list(m+n)
The declared type constructor list takes a type τ
and a type index n(of sort int) to form a type (τ)list(n)
for lists of length n in which each element is of type τ.
The constructors of ’a list are then assgn depent types:
• nil <| ’a list(0)
(* nil is an ’a list of length 0. *)
• cons <| {n:nat} ’a * ’a list(n) -> ’a list(n+1)
(* cons yields an ’a list of length n+1 when given a pair
consisting of an elem of type ’a & an ’a list of lengt n *)
{n:nat} is dependent function type constructor,
written as Πn : nat. Seen as universal quantifier.
The where clause in the declaration of
append is a type annotation, which precisely states
that append returns a list of length m + n.
Constraint Domains
:
Traditionally, index objects are language expressions.
• Instead our lang is "parameterize over a domain of
constraints" from which type index objects are drawn.
Examples include:
• Linear inequalities over integers
• Boolean constraints
• Finite Sets
Integer Constraint Domain
:We use a for index variables. index expressions i, j ::= a | c | i + j | i – j | i * j | i / j | … index propositions P, Q ::= i < j | i <= j | i > j | i >= j | i = j | i <> j | P ∧ Q | P ∨ Q index sorts γ ::= int | {a : γ | P } index variable contexts φ ::= . | φ, a: γ | φ, P index constraints Φ ::= P | P ⊃ Φ | ∀a: γ. Φ satisfaction relation φ |= Φ
Index sort :
Constraints themselves are typed.
We call the types of the constraint lang "index sorts".
Here {a : γ | P} is the subset index sort
for those elements of γ satisfying proposition P.
For instance, nat is an abbreviation for
{a : int | a ≥ 0}.
The satisfaction relation φ |= Φ means that Φ is sat
in the constraint domain under index context φ.
Important Points :
♥ Family of types Indexed by type
1.Distinction between two water Tight worlds.
2.Type checking reduced to Constraint Solving.
3.Property became Physical Value
4.Decleration common type definition : refactoring
Universal Dependent Types :
families δ ::= families of builtin,user-dec refined type
constructor signature S ::= · | S, c : Πa1 : γ1
. . . Πan : γm.τ → δ(i)
major types µ ::= δ(i) | (τ1 ∗ τ2) | (τ1 → τ2)
types τ ::= µ | (Πa : γ.τ)
For instance, int(0), bool array(16);
nat = [a:int | a >= 0] int(a);
{a:int | a >= 0} int list(a) -> int list(a)
Typing Rule and Judgement :
typing judgment φ;Γ |- e : t
φ |- τ1 ≡ τ2
φ;Γ |= e:τ1 φ |= τ1 ≡ τ2
---------------------------
φ;Γ |= e:τ2
φ- index context , Γ- type context
# For rest refer Paper #
An expression in MLΠ0 (C):
fix append : Πm : nat.Πn :
nat.intlist(m) ∗ intlist(n) → intlist(m + n).
λm : nat.λn : nat.lam l : intlist(m) ∗ intlist(n).
case l of
〈nil,ys〉 ⇒ ys
〈cons[a](〈x , xs〉), ys〉 ⇒
〈cons[a + n](〈x, append[a][n](〈xs,ys〉)〉)
Lets Type Check It :
Problem ?
If we apply the filter function to a list of length n,
we cannot express the length of the resulting list
since it depends on the predicate p.
What happens when we can’t check list length?
filter : (’a -> bool) ’a list(n) -> ’a list(?)
Solution Existential Dependent Types :
∃m ≤ n such that the length of the returned list is m.
** NOt Going into Details **
Constructing DML(C) :
ML 0 ← MLΠ 0 ← ML0 Π,Σ ← DML(C)
• ML 0:
• Explicitly typed
• Overly verbose
• Type checking is reduced to constraint
satisfaction in C
• ML0 Π
- Add universal dependent types
• ML0 Π,Σ
- Add Existential types
Red-Black Trees :
Recall Red-Black Trees:
• Every node is either red or black.
• All leaves are black.
• For every node the black height of its children is equal
• Both children of any red node are black.
Red-Black Trees :
type ’a entry = int * ’a
datatype ’a dict =
| Empty (*consideredblack*)
| Black of ’a entry * ’a dict * ’a dict
| Red of ’a entry * ’a dict * ’a dict
typeref ’a dict of bool * nat with
| Empty <| ’a dict(true,0)
| Black <| {cl:bool}{cr:bool}{bh:nat} ’a entry *
’a dict(cl,bh) * ’a dict(cr,bh) -> ’a dict(true,bh+1)
| Red <| {bh:nat} ’a entry * ’a dict(true,bh)
* ’a dict(true,bh) -> ’a dict(false,bh)
Dead Code Elimination :
exception zipException
fun(’a,’b)
| zip(nil,nil) = nil
| zip(cons(x,xs),cons(y,ys)) =
cons((x,y),zip(xs,ys))
| zip( _,_ ) = raisezipException
dependent types
By ashleel baba
dependent types
Dependent ML DML0(C)
- 1,393