**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.

**Polymorphism**

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.

**Type Inference**

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.

**Constraints**

**Constants** have a precise monotype

`3.0:real,4:int,true:bool,"abc":string`

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**

**Overloading**

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.

**Equality**

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.

Tue Apr 15 16:26:05 PDT 1997