The utility of type models is that they are smaller than models in which a general computation can be supported. This means that they can serve a useful purpose in predicting whether an error will occur.
In Computer Science, types serve two major purposes:
In their first role, type-systems can be regarded as a kind of weak logic, capable of inferring that certain events, called type-errors cannot occur. The most important property of a type system is that type-correctness of a program must be decidable. From this requirement, it is clear that not all errors are type-errors, since failure of a program to terminate should clearly be regarded as an error, but the halting problem is undecidable.
If we want to examine the idea of a type-system from the point of view of Combinatory Models, the natural approach is to introduce the idea of a set of exceptions in the model. If an expression can evaluate to an exception, then it should be regarded as erroneous.
EX1
(
d) =
for
EX2
(d
) =
for
K c x = c
S f g x = (f x) (g x)
We denote the type of procedures of
by Proc(
).
If d
,
we say that d has the (weak) type
TD
TR if
d
TD
TR.
It should be noted that given our existing type-descriptive
apparatus
no unique procedure-type can be ascribed to a procedure. For a
given procedure object d it is possible that p
TD1
TR1 and also p
TD2
TR2
where there is way of expressing these two relationships in the form of
p
TD3
TR3
without losing useful discriminatory power. For example, the absolute
value procedure in the FSM has among its types:
But the second of these statements does not subsume the first, because the first statement tells us the relevant fact that if we give abs an integer as argument it returns an integer as result.
If TD1, TD2, TR1, TR2,
are types for which
TD2 TD1 and
TR1
TR2,
then
Let p TD1
TR1 .
Then (p
d1)
TR1
for all d1
TD1 .
But TD2 TD1. Hence
for all
d2
TD2,
(p
d2)
TR1.
Since however TR1
TR2 ,
we see that
(p
d2)
TR2 .
Thus we have shown that any
p TD1
TR1
maps TD2 to TR2, thus establishing our lemma.
A consequence of the contravariance rule is that, for example, despite
the fact that Integer Number, the type
Integer
Integer is not contained in
the type Number
Number. Thus, for
example, the intersection
is non-redundant.
A simple converse of these two lemmas is clearly not true of all combinatory algebras.
for consider a combinatory algebra without procedure objects. Then
TD TR is always the empty-set for
any TR which contains no exceptions, so that
TD1
TR1
TD2
TR2 is true for any combinatory algebras and ranges
whatever.
Since the combinators are denizens of every combinatory algebra, let's start with their type.
Let t T. Then
I
t
= t. Thus I
T
T.
It is sufficient to show that if f
T1
T2
T3
then (S
f)
(T1
T'2)
T1
T3
Hence it suffices to show that if, in addition, g
T1
T'2 then
(S
f
g)
T1
T3 .
Hence it suffices to show that if, in addition,
x T1 then
S
f
g
x
T3 .
But S
f
g
x = (f
x)
(g
x). Since x
T1 , and f
T1
T2
T3 , it follows that (f
x)
T2
T3.
Likewise (g
x)
T'2.
But
T'2
T2 ,
so that ((f
x)
(g
x))
T3 . Hence
(S
f
g
x) in T3 ,
hence (S
f
g) in
T1
T3 ,
hence (S
f)
(T1
T'2)
T1
T3 ,
hence
One interpretation of the above results is that a particular type for one of the combinators is as an intersection. For example, for any two types T1 and T2:
And in general, for any family (Tj) of types:
This is quite easily realised in a simple applicative algebra. For
example, consider an algebra which has the Scheme integers and floats,
together with the abs procedure, which takes the absolute
value of a number. Then
we can take Integer,
Float, {abs},
as separate types, obtaining a finite applicative algebra:
(Integer Integer) =
(Integer Float) =
(Float Float) =
(Float Integer) =
({abs} Integer) = Integer
({abs} Float) = Float
({abs} {abs}) =
A projection mapping
always induces a partition of its
domain into pairwise disjoint sets whose union is the whole domain.
Let ti, t'i Ti
and
tj, t'j
Tj
Let (ti
tj)
.
Tk. Then (ti
t'j)
Tk by HM1, and hence
(t'i
t'j)
.
Tk by HM2. Thus the
operation is
well-defined.
Given a congruence partition of an applicative algebra, where
d Ti
we write [[d]] for Ti. Thus from
definition CP we see that
Suppose our applicative algebra is a combinatory algebra. Then it is easy enough to extend the above lemma to show that a congruence partition of our combinatory algebra is itself a combinatory algebra. Since K and S are defined equationally, the following lemma is an instance of a well known theorem of Universal Algebra. However, we give here an elementary proof.
([[S]] [[d1]]
[[d2]]
[[d3]]) =
[[(S
d1
d2
d3) ]]
= [[(d1 d3)
(d2
d3) ]]
= [[((d1
d3)
(d2
d3))]]
= (([[d1]] [[d3]])
([[d2]]
[[d3]]))
To extend these ideas to a combinatorial model we need to meet the
" conditions" of the combinatory model. But these are not
equational, and so are not automatically satisfied by the
idea of congruence as defined, just as for example the quotient
of an integral domain by an ideal is not necessarily an integral domain.
Saying "there are no divisors of zero" is not an equational statement.
Thus while the integers form an integral domain, the ring of integers
modulo six has divisors of zero, namely [[3]] and [[2]].
We can approach this problem from another point of view. Let's introduce the idea of monomorphic procedure types
The concept is of course too restrictive to serve to characterise
all of the types of SML procedure, which are parametrically
polymorphic. It' also too restrictive to characterise the
S, K, I combinators which are likewise parametrically polymorphic.
But it does give us a start in letting us create an applicative algebra
of types with a simple definition of the
operator, and
which is extensional with respect to its procedure-types.
Thus TD1 and TD2 have an element in common, and being members of the partition, TD1= TD2
Also
p d
TR1
and
p
d
TR2,
since .
d
TD1
and
d
TD2.
Thus
TR1, TR2 have an element in common, and
being members of the partition, TR1= TR2
Hence the result.
It is not hard to construct monomorphically partitioned applicative algebras
with a finite collection of procedure objects, and a finite partition.
But adding combinators gives rise to an infinite collection of procedure
objects, which require an extension of the idea of monomorphic functional types.
Consider for example, the I combinator. It can take as its argument
any object. However our requirement that objects be
partitioned into distinct types does not allow us to have the
idea of type-union, and indeed, a characterisation of I
in terms of type-union is too imprecise. For, while I has the (weak)
type TD TD where TD is the
carrier set of
, this does not capture the fact that
I
T
T for all types
T, that is to say, that
I
i
(Ti
Ti)
for any family of types (Ti).