Let-polymorphism
When extending the type inference for the STLC towards polymorphism, one has to define when it is admissible to derive an instance of a value.
Ideally, this would be allowed with any use of a bound variable, as in the next example where the f
parameter would be instantiated once at Int
and once at String
:
We have a lambda abstraction, (λf. (f 3, f "abc"))
, applied to an arg (λx.x)
(really, the id
fucntion). The arg gets bound to the formal param f
that occurs twice in the lambda's body, both times in a position of application, but each time to a distinct type; first to 3 :: Int
, then to "abc" :: String
.
In Haskell, we'd expect this work, but it doesn't! It would work if both args are of the same type, but since they are not, this fails. The reasone is that the type inference is undecidable in a polymorphic λ-calculus. This means we can make this work by adding the approapraite type annotation ourselves:
This signature makes ps
a Rank-2 function because forall
appears in the parens on the LHS of the second, outer (->). This means that the caller of this function must pass in a (function) arg that can be applied to any type at all; the caller doesn't choose the type (as usual), but the author of the ps
function does.
In polymorphic λ-calculus type inference is undecidable.
Hindley-Milner type system goes around this problem by providing a special form that allows polymorphism, viz. a let-expression. The let-expression (let-binding, let-clause) is a language construct that allows polymorphism, and so it is called let-polymorphism (first introduced in ML).
As we've seen, ML doesn't allow polymorphic binding in a lambda abstraction. This is (probably) because a lambda abstraction is merely a function definition, not necessarily followed by an argument; without immediately knowing the type of the arg, not much can be infered about a function. This is unlike the let-expression, which is equavalent to a lambda abstraction with an arg present.
ML has restricted the binding mechanism by introducing a special form of expression in the language syntax, called let-expression, in which a polymorphic binding is allowed (unline a lambda abstraction, where it's not).
Only values bound in a
let
construct are subject to instantiation, i.e. are polymorphic (sof
is polymorphic). On the other hand, the parameters in lambda-abstractions are treated as being monomorphic.
Last updated
Was this helpful?