Catriel Beeri Pls/Winter 2004/5 last 1 Two comments on let polymorphism I. What is the (time, space) complexity of type reconstruction? In practice – executes “fast” (seems linear time) But, some bad cases exist
Dec 18, 2015
Catriel Beeri Pls/Winter 2004/5 last 1
Two comments on let polymorphism
I. What is the (time, space) complexity of type reconstruction?
In practice – executes “fast” (seems linear time)
But, some bad cases exist
Catriel Beeri Pls/Winter 2004/5 last 2
consider:
let f1 = fun x (x,x);;
let f2 = fun y f1(f1 y);;
let f3 = fun y f2(f2 y);;
…..…. fn …. fn (some expression that uses fn)
How do the types of these functions look like?
Catriel Beeri Pls/Winter 2004/5 last 3
let f1 = fun x (x,x);;
‘a ‘a * ‘a (1 2)
let f2 = fun y f1(f1 y);;
‘a (‘a * ‘a) * (‘a * ‘a) (1 4)
let f3 = fun y f2(f2 y);;
‘a ( [(‘a * ‘a)*(‘a * ‘a)]*[(‘a * ‘a)*(‘a * ‘a)] )*
( [(‘a * ‘a)*(‘a * ‘a)]*[(‘a * ‘a)*(‘a * ‘a)] )
(1 16)
let fn = … (double exponential)
121 2n-
®
Catriel Beeri Pls/Winter 2004/5 last 4
One can save a lot of space by representing types as graphs, instead of trees (common sub expression elimination)
Double exponential exponential
a a a a a
**
*
*
*
Catriel Beeri Pls/Winter 2004/5 last 5
Theorem:
Type reconstruction for core ML is exptime-complete
This means that worst-case complexity is bad, but in practice it is sufficiently efficient
Note: extending type reconstruction to the full calculus with universal types is impossible --- type reconstruction for this calculus is undecidable
Catriel Beeri Pls/Winter 2004/5 last 6
II. polymorphic references are problematic:
let c = ref (lambda x.x);;
here, the type for c is
c:= lambda x. x+5;;
type-checker allows the assignment, type is unit
(!c) true;;
type checker accepts
but, at run-time we apply a function of type intint to true – a run-time error
.ref ( )a a a" ®
Catriel Beeri Pls/Winter 2004/5 last 7
One possible solution: lazy evaluation of let :
let x = e // create binding xe
….
… x // substitute e for x, and continue evaluation
In the example:let c = ref (lambda x. x) // bind c to the expression
c:= lambda x. x+5 // substitute binding for x
(ref lambda x.x) := lambda x.x+5 // one cell created)
(!c) true // substitute binding for x
(!(ref lambda x. x)) true // another cell created
Catriel Beeri Pls/Winter 2004/5 last 8
But • Nobody really knows how to specify or implement
lazy evaluation for languages with imperative features (side-effects) – how to order the side-effects?
• The examples shows this leads to a semantics that is not very useful
Catriel Beeri Pls/Winter 2004/5 last 9
The ML solution:
In let x = e in …
Allow to generalize the type for x only if e is a syntactic value
is
is not
is not
Statistics collected on systems w/o this restriction (a more liberal but complex solution) there are almost no programs where this restriction hurts.
λx.x(λx.x)(λx.x)
ref(λx.x)
Catriel Beeri Pls/Winter 2004/5 last 10
Object-oriented languages – some concepts
A well known feature of OO pl’s is
sub-type polymorphism
We concentrate on this subject
Catriel Beeri Pls/Winter 2004/5 last 11
What is sub-type ?
Two possible answers:
A type t is (denotes) a set of values
With the second, int<: float holds;
Compiler inserts the coercion during type-checking
(so a bit more complexity of type-checking is expected) We use the first (simpler intuition)
§ ¨ § ¨ type is a sub-type of τ, denoted :τ if τ < S Ss s s Íg
§ ¨ § ¨ type is a sub-type of τ, denoted :τ if<
the coercion function re exists a from to τ S S
s s
s
g
§ ¨tS
Catriel Beeri Pls/Winter 2004/5 last 12
The basic intuition of sub-typing:
List to the type-checker level :
an expression of a sub-type can be safely used in a context where an expression of a type is expected
use is defined by the operations available on the two types sub-typing is not a new independent feature, it interacts with the other components of a type system
if :τ holds, then an element of can be <
wherever an element of τ is
used
expected
s s
Catriel Beeri Pls/Winter 2004/5 last 13
Sub-typing with records and cells
Objects are similar to records convenient to introduce sub-typing in the context of a language with :
base types, records, functions, ref cells
We assume some (possibly none) sub-type axioms are given for the base types
Catriel Beeri Pls/Winter 2004/5 last 14
From the basic intuition :
The interaction of sub-typing with the type-checker :
the subsumption rule:
Wherever the type-checker expects a type, it allows a sub-type
Note: algorithmically, this rule is problematic
| : :τ<(subsm) | : τ
H e
H e
s s--
Catriel Beeri Pls/Winter 2004/5 last 15
Rules independent of the given type system: From the basic intuition, sub-typing is reflexive and
transitive
Second rule also looks a bit problematic (algorithmically)
(refl) :<s s
:τ τ :< <(trans) :<
s ms m
Catriel Beeri Pls/Winter 2004/5 last 16
Rules for records :
Example :
let f = lambda x : {a:int} . x.a;;
seems reasonable to apply f also to {a=4, b=“john”}, since f uses only x.a
But, also make sense to allow a sub-type in a field
1 1(rec-width) { : } :{ : }<n k n
i i i i i ia as s+= =
i
1 1
:τ [1.. ]<(rec-depth) { : } :{ : τ }<
in n
i i i i i i
i n
a a
ss = =
" Î
Catriel Beeri Pls/Winter 2004/5 last 17
Using these two rules, we can prove:
Using reflexivity, we can refine a single field, rather than all
{ : int, : int} :{ : int} { : int} :{}
{ :{ : int, : int}, :{ : int} :{ :{ : int}, {}}
a b a l
m a b n l m a n
< <<
{ : int, : int} :{ : int} { : int} :{ : int}
{ :{ : int, : int}, :{ : int} :{ :{ : int}, { : int}}
a b a l l
m a b n l m a n l
< <<
Catriel Beeri Pls/Winter 2004/5 last 18
By combining the two record rules with transitivity, we can change both the number of fields and their types
{ :{ : int, : float}, :{ : int}}
:{ :{ : int, : float}}
m a b n l
m a b<{ : int, : float} :{ : int}
{ :{ : int, : float} : :{ : int}}
a b a
m a b m a
<<
{ :{ : int, : float}, :{ : int}} :{ :{ : int}}m a b n l m a<
Catriel Beeri Pls/Winter 2004/5 last 19
Can combine to one comprehensive record rule:
Note: we assume that in a record, order of fields is irrelevant, so in all the rules, the label-type pairs are assumed to be a set.
This can be emphasized by a rule that allows to change position of fields
Can “add” fields anywhere in a record
i
1 1
: τ [1.. ](rec-general)
{ : } :{ : τ }i
n k ni i i i i i
i n
a a
ss +
= =
" Î<<
Catriel Beeri Pls/Winter 2004/5 last 20
Rules for functions :
These can be applied, be passed as arguments/return values
If a context requires a function that for an argument of type return a value of type , then a function that returns a value of a sub-type is ok
1 2
1 2
τ : τ(fun-out) ( )
τ : τco-variance
s s<
® ®<
s 2τ
Catriel Beeri Pls/Winter 2004/5 last 21
But, for the input type:
In a context that expects a function of this type, you also accept a function that has this guarantee for a larger set
2 1
1 2
contra-varianc:
(fun-in) ( )τ τ
e:
s ss s
<® ®<
The type τ is a gurantee:
if you supply a value of type
the return value will be certainly of type τ
hence, value of type is allowed aan s puy in t
s
s
s
®
Catriel Beeri Pls/Winter 2004/5 last 22
The two rules are typically combined :
Contra-variance for the input type is difficult to swallow; convince yourself that
There are also applications where a restriction of the in-type in a co-variant fashion seems desirable
Some languages (e.g., Eiffel) also co-variant change on in-type, and leave a hole in the type system
2 1 1 2
1 1 2 2
: τ : τ(fun)
τ : τ
s ss s
< <® ®<
§ ¨ § ¨1 2 2 1τ is a subset of τ only if : S Ss s s s® ® <