Type inference using type constraints

Definition (seen in class):

A Type-substitution is a mapping, s, from a finite set of type-variables to a finite set of type-expressions, such that for every type-variable T, s(T) does not include T. A type-binding is a pair <T,s(T)> such that T = s(T). Type-Substitutions are written using set notation, for example :

Question 1

Typing statement

A typing statement is a true/false formula that states a judgment about the type of a language expression, given a type environment.

It has the notation: Tenv ⊢ e:T, which reads: under the type-environment Tenv, the expression e has type T.

E.g., {x:Number} ⊢ (+ 3 x):Number states that under the assumption that the type of x is Number, the type of (+ 3 x) is Number. For the typing statement below, note whether they are true or false:

Question 2

A typing-statement is based on assumptions in a given type-environment. The less assumptions are involved, the stronger is the statement. In order to end up with the strongest statement, we follow a simple heuristic rule: always pick a minimal type environment (or: always infer the strongest statement possible). For each row of statements below, which statement is stronger? left or right ?

Note : assumptions in Tenv are an added part to the axioms we have.

Term 1 Term 2
{foo: [T1->T2]} ⊢ 5: Number {} ⊢ 5: Number
{x: Number} ⊢ (+ x 3): Number {y: Number,x: Number} ⊢ (+ x 3): Number
{} ⊢ (lambda (x)(+ x 3)):[Number -> Number] {y: Number} ⊢ (lambda (x)(+ x y)):[Number -> Number]
(Can we compare these two?)
{} ⊢ (lambda (x)(+ x 3)):[Number -> Number] {y:Number} ⊢ (lambda (z)(+ z 3)):[Number -> Number]
{f:[Number -> Number]} ⊢ ((lambda (f x) (f x))(lambda (x) (* x x)) 10): Number {} ⊢ ((lambda (f x) (f x)) (lambda (x) (* x x)) 10): Number

Note: A typing statement has to be true in order to determine its strength.

Definitions (seen in class):

An application of a type-substitution s to a type-expression TE, denoted by TE ○ s, is a consistent replacement of type-variables T in TE by their mapped type-expressions s(T). For example:

Question 3

A unifier of type expressions TE1, TE2 is a type substitution s such that TE1 ○ s = TE2 ○ s (the type expressions should not include common type variables). The most general unifier (MGU), is a unifier such that any other unifier is an instance of it.

Recall the lecture’s definition of “instance of type expression” : T’ is an instance of type expression T, if there is a type substitution s such that T o s = T'.

In case of an instance of the MGU type substitution, it is any type substitution s such that for each type expression e in s, e is an instance of a type expression in our MGU. All other unifiers are obtained from it by application of additional substitutions.

Find the MGU for the following pairs of type-environments:

Type expressions MGU
{x: T1}, {x: Number} {T1=Number} (a non-MGU unifier: {T1=Number, T2=B})
{x: T1}, {x: T2} {T1=T2} (a non-MGU unifier: {T1=Number, T2=Number})
{x: [T1*[T1->T2]->T2]}, {x: [Number * [T3->T4]->T4]} {T1=Number, T3=Number, T4=T2}
{x: [T1*[T1->T2]->Number]}, {x: [[T3->T4] * [T5->Number]->Number]} {T1=[T3->T4], T5=[T3->T4], T2=Number}
{x: [T1*[T1->T2]->Number]}, {x: [Number * [Symbol->T3]->Number]} No unifier

Type inference using type constraints

Typing rules

Question 1

Typing the expression ((lambda (f1 x1) (f1 x1)) sqrt 4): => ((lambda ([f1 : Tf] [x1 : Tx]) : T2 (f1 x1)) sqrt 4)

Note: See how we added type anotations to the lambda’s params, and return value.

Stage I: Rename bound variables.

((lambda (f1 x1) (f1 x1)) sqrt 4) turn to ((lambda (f x) (f x)) sqrt 4)

Stage II: Assign type variables for every sub expression:

Expression Variable
((lambda (f x) (f x)) sqrt 4) T0
(lambda (f x) (f x)) T1
(f x) T2
f Tf
x Tx
sqrt Tsqrt
4 Tnum4

Stage III: Construct type equations.

The equations for the sub-expressions are:

Expression Equation
((lambda (f x) (f x)) sqrt 4) T1 = [Tsqrt * Tnum4 -> T0]
(lambda (f x) (f x)) T1 = [Tf * Tx -> T2]
(f x) Tf = [Tx -> T2]

The equations for the primitives are:

Expression Equation
sqrt Tsqrt = [Number -> Number]
4 Tnum4 = Number

Stage IV: Solve the equations.

Equation Substitution
1. T1 = [Tsqrt * Tnum4 -> T0] {}
2. T1 = [Tf * Tx -> T2]  
3. Tf = [Tx -> T2]  
4. Tsqrt = [Number -> Number]  
5. Tnum4 = Number  

Step 1:

(T1 = [Tsqrt * Tnum4-> T0]) ○ Substitution = (T1 = [Tsqrt * Tnum4-> T0]) and is a type-sub.

Substitution = Substitution ○ (T1 = [Tsqrt * Tnum4-> T0]).

Equation Substitution
2. T1 = [Tf * Tx -> T2] {T1 := [Tsqrt * Tnum4 -> T0]}
3. Tf = [Tx -> T2]  
4. Tsqrt = [Number -> Number]  
5. Tnum4 = Number  

Step 2:

T1 = [Tf * Tx -> T2] ○ Substitution = ([Tsqrt * Tnum4 -> T0] = [Tf * Tx -> T2]) There is not type-sub since both sides of the equation are composite we split it into three equations (6,7,8) and remove equation 2.

Equation Substitution
3. Tf = [Tx -> T2] {T1 := [Tsqrt * Tnum4 -> T0]}
4. Tsqrt = [Number -> Number]  
5. Tnum4 = Number  
6. Tf = Tsqrt  
7. Tx = Tnum4 (or Tnum4 = Tx)  
8. T2 = T0  

Step 3:

(Tf = [Tx -> T2]) ○ Substitution = (Tf = [Tx -> T2]). Substitution = Substitution ○ (Tf = [Tx -> T2]).

Equation Substitution
4. Tsqrt = [Number -> Number] {T1 := [Tsqrt * Tnum4 -> T0], Tf := [Tx -> T2]}
5. Tnum4 = Number  
6. Tf = Tsqrt  
7. Tx = Tnum4 (or Tnum4 = Tx)  
8. T2 = T0  

Step 4:

(Tsqrt = [Number -> Number]) ○ Substitution = (Tsqrt = [Number -> Number]). Substitution = Substitution ○ (Tsqrt = [Number -> Number]).

Equation Substitution
5. Tnum4 = Number { [T1 :=[[Number -> Number] * Tnum4->T0],
       Tf := [Tx -> T2], Tsqrt := [Number -> Number]}
6. Tf = Tsqrt  
7. Tx = Tnum4  
8. T2 = T0  

Step 5:

(Tnum4 = Number) ○ Substitution = (Tnum4 = Number), is a type-sub. Substitution = Substitution ○ (Tnum4 = Number).

Equation Substitution
6. Tf = Tsqrt {     T1 :=[[Number -> Number] * Number->T0],
       Tf := [Tx -> T2], Tsqrt := [Number -> Number],
       Tnum4 := Number    }
7. Tx = Tnum4  
8. T2 = T0  

Step 6:

(Tf = Tsqrt) ○ Substitution = ([Tx -> T2] = [Number -> Number]) There is no a sub-type. We split the equation into two equations (9,10) and remove equation 6.

Equation Substitution
7. Tx = Tnum4 {     T1 :=[[Number -> Number] * Number->T0],
       Tf := [Tx -> T2], Tsqrt := [Number -> Number],
       Tnum4 := Number    }
8. T2 = T0  
9. Tx = Number  
10. T2 = Number  

Step 7:

(Tx = Tnum4) ○ Substitution = ([Tx = Number]), type-sub. Substitution = Substitution ○ ([Tx = Number]).

Equation Substitution
8. T2 = T0 {     T1 :=[[Number -> Number] * Number->T0],
       Tf := [Number -> T2], Tsqrt := [Number -> Number],
       Tnum4 := Number,
       Tx = Number    }
9. Tx = Number  
10. T2 = Number  

Step 8:

(T2 = T0) ○ Substitution = (T2 = T0), type-sub. Substitution = Substitution ○ (T2 = T0).

Equation Substitution
9. Tx = Number {     T1 :=[[Number -> Number] * Number->T0],
       Tf := [Number-> T0], Tsqrt := [Number -> Number],
       Tnum4 := Number,
       Tx = Number,
       T2 := T0
         }
10. T2 = Number  

Step 9: (Tx = Number) ○ Substitution = (Number = Number) always true.

Equation Substitution
10. T2 = Number {     T1 :=[[Number -> Number] * Number->T0],
       Tf := [Number-> T0],
       Tsqrt := [Number -> Number],
       Tnum4 := Number,
       Tx = Number ,
       T2 := T0     }

Step 10:

(T2 = Number) ○ Substitution = (T0 = Number), type-sub. Substitution = Substitution ○ (T0 = Number).

Equation Substitution
  {     T1 :=[[Number -> Number] * Number->Number],
       Tf := [Number-> Number],
       Tsqrt := [Number -> Number],
       Tnum4 := Number,
       Tx = Number ,
       T2 := Number
       T0 := Number     }

The type inference succeeds since we have a type for T0, meaning that the expression is well typed. Since there are no free variables, the inferred type of T0 is: Number.

Note: Our expression can be written now as ((lambda ([f : (Number -> Number)] [x : Number]) : Number (f x)) sqrt 4)

Question 2

Extending the typing mechanism for if expressions: Recall the typing rule for if expressions shown in the typing system:

### Typing rule of If experession :
For every: type environment _Tenv, 
           expressions _p, _c, _a,
           and type expressions Boolean, _Tif:
If         _Tenv ⊢ _p:Boolean,
           _Tenv ⊢ _c:_Tif,
           _Tenv ⊢ _a:_Tif
Then _Tenv ⊢ (if _p _c _a):_Tif

Questions:

First thing we notice from the rule is that the consequence expression (_c) and the alternative expression (_a) have the same type.

Given the first observation, the second thing we notice is that the type of the if expression is the type of the consequence expression.

Given the two observations we can add the following equations:

Expression	 Equation
(if _p _c _a)	T_p = Boolean
                T_c = T_a
            	Tif = T_c

Example: type the expression (if #t (+ 1 2) 3)

Again, look how we add type annotations.

Stage I: Rename bound variables: No reference of variables so no renaming is needed.

Stage II: Assign type variables for every sub expression:

Expression Variable
(if #t (+ 1 2) 3) T0
(+ 1 2) T1
+ T+
#t T#t
1 Tnum1
2 Tnum2
3 Tnum3

Stage III: Construct type equations. The equations for the sub-expressions are:

Expression Equation
(if #t (+ 1 2) 3) T#t = Boolean
  T1 = Tnum3
  T0 = T1
(+ 1 2) T+ = [Tnum1 * Tnum2 -> T1]

The equations for the primitives are:

Expression Equation
+ T+ = [Number * Number -> Number]
#t T#t = Boolean
1 Tnum1 = Number
2 Tnum2 = Number
3 Tnum3 = Number

Stage IV : Solve the equations:

Equation Substitution
1. T#t = Boolean {}
2. T1 = Tnum3  
3. T0 = T1  
4. T+ = [Tnum1 * Tnum2 -> T1]  
5. T+ = [Number * Number -> Number]  
6. T#t = Boolean  
7. Tnum1 = Number  
8. Tnum2 = Number  
9. Tnum3 = Number  

Step 1:

(T#t = Boolean) ○ Substitution = (T#t = Boolean), type-sub.

Substitution = Substitution ○ (T#t = Boolean).

Equation Substitution
2. T1 = Tnum3 {    T#t = Boolean     }
3. T0 = T1  
4. T+ = [Tnum1 * Tnum2 -> T1]  
5. T+ = [Number * Number -> Number]  
6. T#t = Boolean  
7. Tnum1 = Number  
8. Tnum2 = Number  
9. Tnum3 = Number  

Step 2:

(T1 = Tnum3) ○ Substitution = (T1 = Tnum3), type-sub.

Substitution = Substitution ○ (T1 = Tnum3).

Equation Substitution
3. T0 = T1 {T#t = Boolean, T1 := Tnum3}
4. T+ = [Tnum1 * Tnum2 -> T1]  
5. T+ = [Number * Number -> Number]  
6. T#t = Boolean  
7. Tnum1 = Number  
8. Tnum2 = Number  
9. Tnum3 = Number  

Step 3:

(T0 = T1) ○ Substitution = (T0 = Tnum3), type-sub.

Substitution = Substitution ○ (T0 = Tnum3).

Equation Substitution
4. T+ = [Tnum1 * Tnum2 -> T1] {    T#t = Boolean,
       T1 := Tnum3,
       T0 := Tnum3     }
5. T+ = [Number * Number -> Number]  
6. T#t = Boolean  
7. Tnum1 = Number  
8. Tnum2 = Number  
9. Tnum3 = Number  

Step 4:

(T+ = [Tnum1 * Tnum2 -> T1]) ○ Substitution = (T+ = [Tnum1 * Tnum2 -> Tnum3]), type-sub.

Substitution = Substitution ○ (T+ = [Tnum1 * Tnum2 -> Tnum3]).

Equation Substitution
5. T+ = [Number * Number -> Number] {    T#t = Boolean,
       T1 := Tnum3,
       T0 := Tnum3,
       T+ = [Tnum1 * Tnum2 -> Tnum3]     }
6. T#t = Boolean  
7. Tnum1 = Number  
8. Tnum2 = Number  
9. Tnum3 = Number  

Step 5:

(T+ = [Number * Number -> Number]) ○ Substitution = ([Tnum1 * Tnum2 -> Tnum3] = [Number * Number -> Number])

There is not a type-sub. We split the equation to Tnum1 = Number, Tnum2 = Number and Tnum3 = Number, and add them to the equations. Since they already exists, we only need to remove equation 5.

Equation Substitution
6. T#t = Boolean {    T#t = Boolean,
       T1 := Tnum3,
       T0 := Tnum3,
       T+ = [Tnum1 * Tnum2 -> Tnum3]     }
7. Tnum1 = Number  
8. Tnum2 = Number  
9. Tnum3 = Number  

Step 6: (T#t = Boolean) ○ Substitution = (Boolean = Boolean) always true.

Equation Substitution
7. Tnum1 = Number {    T#t = Boolean,
       T1 := Tnum3,
       T0 := Tnum3,
       T+ = [Tnum1 * Tnum2 -> Tnum3]     }
8. Tnum2 = Number  
9. Tnum3 = Number  

Skipping the trivial steps, we get:

Equation Substitution
  {     T#t := Boolean,
      T1 := Number,
       T0 := Number,
      Tnum1 := Number,
      Tnum2 := Number,
      Tnum3 := Number,
       T+ := [Number * Number -> Number]    }

The type inference succeeds, meaning that the expression is well typed. Because there are no free variables, the inferred type of T0 is: Number.

Question 3

Typing the application ((lambda (f1 x1) (f1 x1)) 4 sqrt):

Stage I: Rename bound variables.

((lambda (f1 x1) (f1 x1)) 4 sqrt) turns into ((lambda (f x) (f x)) 4 sqrt)

Stage II: Assign type variables for every sub expression and primitives:

Expression Variable
((lambda (f x) (f x)) 4 sqrt) T0
(lambda (f x) (f x)) T1
(f x) T2
f Tf
x Tx
4 Tnum4
sqrt Tsqrt

Stage III: Construct type equations.

The equations for the sub-expressions are:

Expression Equation
((lambda (f x) (f x)) 4 sqrt) T1 = [Tnum4 * Tsqrt -> T0]
(lambda (f x) (f x)) T1 = [Tf * Tx -> T2]
(f x) Tf = [Tx -> T2]

The equations for the primitives are:

Expression Equation
4 Tnum4 = Number
sqrt Tsqrt = [Number -> Number]

Stage IV: Solve the equations.

Equation Substitution
1. T1 = [Tnum4 * Tsqrt -> T0] {}
2. T1 = [Tf * Tx -> T2]  
3. Tf = [Tx -> T2]  
4. Tnum4 = Number  
5. Tsqrt = [Number -> Number]  

Step 1:

(T1 = [Tnum4 * Tsqrt -> T0]) ○ Substitution = (T1 = [Tnum4 * Tsqrt -> T0]), type-sub.

Substitution = Substitution ○ (T1 = [Tnum4 * Tsqrt -> T0]).

Equation Substitution
2. T1 = [Tf * Tx -> T2] {     T1 := [Tnum4 * Tsqrt -> T0]    }
3. Tf = [Tx -> T2]  
4. Tnum4 = Number  
5. Tsqrt = [Number -> Number]  

Step 2:

(T1 = [Tf * Tx -> T2]) ○ Substitution = ([Tf * Tx -> T2] = [Tnum4 * Tsqrt -> T0])

There is no type-sub. We split the equation to

We add them to the equations (6,7,8) and remove equation 2.

Equation Substitution
3. Tf = [Tx -> T2] {     T1 := [Tnum4 * Tsqrt -> T0]    }
4. Tnum4 = Number  
5. Tsqrt = [Number -> Number]  
6. Tf = Tnum4  
7. Tx = Tsqrt  
8. T2 = T0  

Step 3:

(Tf = [Tx -> T2]) ○ Substitution = (Tf = [Tx -> T2]) , type-sub. Substitution = Substitution ○ (Tf = [Tx -> T2]).

Equation Substitution
4. Tnum4 = Number {     T1 := [Tnum4 * Tsqrt -> T0],
       Tf = [Tx -> T2]    }
5. Tsqrt = [Number -> Number]  
6. Tf = Tnum4  
7. Tx = Tsqrt  
8. T2 = T0  

Step 4:

(Tnum4 = Number) ○ Substitution = (Tnum4 = Number), type-sub.

Substitution = Substitution ○ (Tnum4 = Number).

Equation Substitution
5. Tsqrt = [Number -> Number] {     T1 :=[Number * Tsqrt -> T0],
       Tf = [Tx -> T2],
       Tnum4 = Number    }
6. Tf = Tnum4  
7. Tx = Tsqrt  
8. T2 = T0  

Step 5:

(Tsqrt = [Number -> Number]) ○ Substitution = (Tsqrt = [Number -> Number]) , type-sub. Substitution = Substitution ○ (Tsqrt = [Number -> Number]).

Equation Substitution
6. Tf = Tnum4 {     T1 :=[Number * [Number -> Number]-> T0],
       Tf = [Tx -> T2],
       Tnum4 = Number
       Tsqrt := [Number->Number]    }
7. Tx = Tsqrt  
8. T2 = T0  

Step 6:

(Tf = Tnum4) ○ Substitution = ([Tx -> T2] = Number)

We get the conflicting equation:

[Tx -> T2] = Number and we can say that the expression is not well typed.