Better Abstraction Mechanisms
Ordinary (first-order, monomorphic) functions allow us to abstract operations away from specific values.
These two functions are fundamentally similar. Can we take advantage of this by making them instances of a single, more abstract, function?
Functional languages permit us to build more powerful abstractions in several ways.
Polymorphism allows us to write functions that work uniformly on container data structures without regard for the contained type.
Higher-order functions allow us to define functions that share a uniform control structure as instances of a single function.
Higher-order abstractions must be written explicitly, but polymorphism comes ``for free.''
Consider these functions:
The first two make perfectly good sense on lists containing any type. The last makes sense on lists containing pairs of any type. Moreover, the function ``does the same thing'' to its argument list regardless of of the underlying types.
Note that SML automatically gives them types in which the ``don't care'' components are denoted by type variables 'a,'b, , pronounced ``alpha, beta, ''.
Unless we explicitly add type constraints, SML will always give every function the most general possible type, allowing the broadest possible re-use.
ML automatically infers the most general (a.k.a. principal type) of every variable and expression in the program. Of course, a given expression might have lots of legal types, but these are all instances of the principal type.
Example: These are all instances of 'a * 'b -> 'a
Initially, every type is free, i.e., an independent type variable. The inference process consists of applying constraints dictated by the program, which pins down the types just as much as required for the program to make sense.
Constants have a precise monotype
Certain built-in operators (but not all!) have a precise monotype.
(op div):int * int->int, chr: int -> string
Tuple constructor applications () always produce a tuple type, but don't dictate the types in the tuple.
List constructor applications nil, ::,  always result in a list type, and force the elements of the list to be the same type, but don't dictate what that type is.
Each arm of a case expression must evaluate to the same type.
For let-bound functions, types of formal parameters are constrained (only) by the way in which parameters are used in the function body. Types of actual arguments to applications of these functions must be instances of the formal argument types.
For functions passed as arguments, things are a little more restrictive; more details later.
Examples for Type inference
The arithmetic operators +,-,*, apply to both real and int types, and the relational operators <,<=,>=,> apply to real, int, and string types. But these operators are not polymorphic, because they do something different to their arguments depending on type. Instead, we say that they are overloaded.
When these operators are used in a program, SML insists that it be possible to figure out the precise base type to which they are being applied. Often this can be determined automatically (e.g., sum). But sometimes it is necessary to give an explicit type constraint to clarify which version of the operator is needed.e.g.:
There is no provision for adding user-defined overloaded operators in SML.
The equality operators (=,<>) are even more special. They are almost polymorphic: they define structural (i.e., component-wise) equality on almost any type except on function types. So we can write a function like:
But we mustn't apply it like this:
The special equality type variables ''a,''b, can only be instantiated to types that don't contain an arrow.