(var) ---------------- x : A |- x : A (abs) ------------------ |- \x.x : A -> A
(var) -------------------------- x : B -> B |- x : B -> B (abs) -------------------------------- |- \x.x : (B -> B) -> (B -> B)In a sense, however, the previous type (A -> A) seems a "better type". In fact, the type (B -> B) -> (B -> B) can be seen as a particular case of A -> A, but not viceversa. In other words, A -> A is more general than (B -> B) -> (B -> B). We can indeed prove that A -> A is the most general (or principal) type of \x.x.
Theorem If a lambda term has a type, then it has a principal type, unique modulo renaming.
We don't give a formal proof of this theorem, but we show how to construct the principal type. Let us start with the example of the term \x.x. Intuitively, any proof of a type statement for \x.x must have the following form:
(var) ---------------- A = B x : A |- x : B (abs) ---------------- C = A -> B |- \x.x : CThe equation C = A -> B indicates the condition under which (abs) is applicable, and the equation A = B indicates the condition under which (var) is applicable. Hence A = B , C = A -> B are the conditions under which the proof is valid. Any solution of these equations (i.e. any substitution which makes A and B identical, and C and A -> B identical), applied to the type in the conclusion (i.e. C), will derive a type for \x.x. Clearly, the most general type is obtained by taking the most general solution of the equations (see section on unification below). One form of the most general solution is the substitution theta = [A/B, A->A/C]. theta, applied to C, gives the type A -> A. (Alternatively we could have considered the substitution [B/A , B->B/C], that would have given the type B -> B, which is equivalent to A -> A modulo renaming.)
the principal type of M is A theta.If, on the contray, the generic proof cannot be built, or the equations are not solvable, then M is not typeable.
- val f = fn x => x;(remember that fn x => E is the ML syntax for \x.E), the ML answer is:
val f = fn : 'a -> 'a(where 'a represents a type variable), meaning that f is a function of type 'a -> 'a.
Note that x x represents the application of a generic function x to itself. There are functions for which it makes sense to be applied to themselves (for instance the identity function), but this is not the case for all functions.
From a semantic point of view, note that if A -> B is to be interpreted as the set of functions from a set A to a set B, then there is no non-trivial set A which can be equal to the set A -> B, for cardinality reasons. In fact, if A has cardinality n, and B has cardinality m, then A -> B has cardinality mn. In domain theory, where it is desirable that such equations have a solution, A -> B is assumed to represent not all functions from A to B, but only a particular class of them.
the inhabited types are exactly the formulas which are valid in the intuitionistic propositional logicwhere -> is to be interpreted as logical implication.
Definition Given a set of variables Var, and a set of function symbols Fun (possibly including constant symbols) the first-order terms are defined by the following grammar:
Term ::= Var | Fun(Term,...,Term)
In the case of type expressions, we have only one binary function symbol (represented in infix notation): the arrow ->.
Definition A substitution theta is any mapping theta : Var -> Term.
A substitution theta will be denoted by listing explicitly the result of its application to every variable (usually we are interested only in finite substitutions, i.e. substitutions which affect only a finite number of variables). More precisely, a substitution theta such that theta(x1) = t1,..., theta(xn) = tn, will be denoted by [t1/x1,..., tn/xn].
The application of a substitution theta to a term t, denoted by t theta, is the term obtained from t by replacing symultaneously each variable x by theta(x).
The composition of two substitutions sigma and theta is the substitution sigma theta s.t. for every variable x, (sigma theta)(x) = (x sigma)theta.
Definition Given a set of equations on terms E = {t1 = u1, ... , tn = un}, a substitution theta is a unifier (solution) for E iff for each i we have that titheta is identical to uitheta. A substitution theta is the most general unifier of E if it is a unifier for E and, for any other unifier sigma, there exists sigma' s.t. sigma = theta sigma' (i.e. sigma can be obtained by instantiating theta).
Example Consider the set of equations
E = {A = B->C , B->C = C->B}We have that
There are various algoriths to find the most general unifier for a set of first order equations; for instance, the algorithm of Martelli-Montanari (see [Apt_Pellegrini, Section 2]. Note that in this reference they use a reversed notation for subsitution: x/t insteand of t/x).
Proposition The algorithm of Martelli-Montanari always terminates and it gives a most general unifier if the set of equations is solvable, failure otherwise.
Corollary Given a set of first order equations E, it is decidable whether E is solvable or not, and, if it is solvable, then it has a most general unifier (which is unique modulo renaming).
------------------- E = B x:B, x:D |- x : E ------------------- C = D -> E x:B |- \x.x : C ------------------- A = B -> C |- \xx.x : Awhich would make you conclude that the type of the \xx.x is B -> D -> B. This is wrong: The type of \xx.x (aka \xy.y) is B -> D -> D and it is different from B -> D -> B. The two types are not even one the instance of the other.
This error comes from the fact that there are two assumptions with the same variable x (x:B, x:D) in one of the assertion. This should never happen, because if you get to that point it means that you don't know anymore which variable (in the assumption) represents the variable with the same name in the body.
In general, you should use different names for all the bound variables, and this problem will never arise.
Another solution would be to modify the abstraction rule so to introduce a sort of rule of scoping. Maybe we will see this technique later in the course.