A Hindley–Milner (HM) type system is a classical
type system
In computer programming, a type system is a logical system comprising a set of rules that assigns a property called a type to every "term" (a word, phrase, or other set of symbols). Usually the terms are various constructs of a computer progra ...
for the
lambda calculus
Lambda calculus (also written as ''λ''-calculus) is a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution. It is a universal model of computation t ...
with
parametric polymorphism
In programming languages and type theory, parametric polymorphism allows a single piece of code to be given a "generic" type, using variables in place of actual types, and then instantiated with particular types as needed. Parametrically polymorph ...
. It is also known as Damas–Milner or Damas–Hindley–Milner. It was first described by
J. Roger Hindley
J. Roger Hindley is a prominent British logician best known for the Hindley–Milner type inference algorithm. Since 1998, he has been an Honorary Research Fellow at Swansea University.
Education
Hindley graduated in 1960 from Queen's Univers ...
and later rediscovered by
Robin Milner
Arthur John Robin Gorell Milner (13 January 1934 – 20 March 2010), known as Robin Milner or A. J. R. G. Milner, was a British computer scientist, and a Turing Award winner. .
Luis Damas contributed a close formal analysis and proof of the method in his PhD thesis.
Among HM's more notable properties are its
completeness and its ability to infer the
most general type of a given program without programmer-supplied
type annotations or other hints.
Algorithm W
In mathematics and computer science, an algorithm () is a finite sequence of rigorous instructions, typically used to solve a class of specific problems or to perform a computation. Algorithms are used as specifications for performing c ...
is an efficient
type inference
Type inference refers to the automatic detection of the type of an expression in a formal language. These include programming languages and mathematical type systems, but also natural languages in some branches of computer science and linguistics. ...
method in practice, and has been successfully applied on large code bases, although it has a high theoretical
complexity
Complexity characterises the behaviour of a system or model whose components interact in multiple ways and follow local rules, leading to nonlinearity, randomness, collective dynamics, hierarchy, and emergence.
The term is generally used to c ...
.
[Hindley–Milner type inference is DEXPTIME-complete. In fact, merely deciding whether an ML program is typeable (without having to infer a type) is itself DEXPTIME-complete. Non-linear behaviour does manifest itself, yet mostly on ]pathological
Pathology is the study of the causes and effects of disease or injury. The word ''pathology'' also refers to the study of disease in general, incorporating a wide range of biology research fields and medical practices. However, when used in t ...
inputs. Thus the complexity theoretic proofs by and came as a surprise to the research community. HM is preferably used for
functional language
In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that ...
s. It was first implemented as part of the type system of the programming language
ML. Since then, HM has been extended in various ways, most notably with
type class
In computer science, a type class is a type system construct that supports ad hoc polymorphism. This is achieved by adding constraints to type variables in parametrically polymorphic types. Such a constraint typically involves a type class T a ...
constraints like those in
Haskell
Haskell () is a general-purpose, statically-typed, purely functional programming language with type inference and lazy evaluation. Designed for teaching, research and industrial applications, Haskell has pioneered a number of programming lan ...
.
Introduction
As a type inference method, Hindley–Milner is able to deduce the types of variables, expressions and functions from programs written in an entirely untyped style. Being
scope
Scope or scopes may refer to:
People with the surname
* Jamie Scope (born 1986), English footballer
* John T. Scopes (1900–1970), central figure in the Scopes Trial regarding the teaching of evolution
Arts, media, and entertainment
* CinemaS ...
sensitive, it is not limited to deriving the types only from a small portion of source code, but rather from complete programs or modules. Being able to cope with
parametric types, too, it is core to the type systems of many
functional programming
In computer science, functional programming is a programming paradigm where programs are constructed by applying and composing functions. It is a declarative programming paradigm in which function definitions are trees of expressions that ...
languages. It was first applied in this manner in the
ML programming language.
The origin is the type inference algorithm for the
simply typed lambda calculus
The simply typed lambda calculus (\lambda^\to), a form
of type theory, is a typed interpretation of the lambda calculus with only one type constructor (\to) that builds function types. It is the canonical and simplest example of a typed lambda ...
that was devised by
Haskell Curry
Haskell Brooks Curry (; September 12, 1900 – September 1, 1982) was an American mathematician and logician. Curry is best known for his work in combinatory logic. While the initial concept of combinatory logic was based on a single paper by ...
and
Robert Feys in 1958.
In 1969,
J. Roger Hindley
J. Roger Hindley is a prominent British logician best known for the Hindley–Milner type inference algorithm. Since 1998, he has been an Honorary Research Fellow at Swansea University.
Education
Hindley graduated in 1960 from Queen's Univers ...
extended this work and proved that their algorithm always inferred the most general type.
In 1978,
Robin Milner
Arthur John Robin Gorell Milner (13 January 1934 – 20 March 2010), known as Robin Milner or A. J. R. G. Milner, was a British computer scientist, and a Turing Award winner. , independently of Hindley's work, provided an equivalent algorithm,
Algorithm W
In mathematics and computer science, an algorithm () is a finite sequence of rigorous instructions, typically used to solve a class of specific problems or to perform a computation. Algorithms are used as specifications for performing c ...
.
In 1982,
Luis Damas finally proved that Milner's algorithm is complete and extended it to support systems with polymorphic references.
Monomorphism vs. polymorphism
In the
simply typed lambda calculus
The simply typed lambda calculus (\lambda^\to), a form
of type theory, is a typed interpretation of the lambda calculus with only one type constructor (\to) that builds function types. It is the canonical and simplest example of a typed lambda ...
, types are either atomic type constants or function types of form
. Such types are ''monomorphic''. Typical examples are the types used in arithmetic values:
3 : Number
add 3 4 : Number
add : Number -> Number -> Number
Contrary to this, the untyped lambda calculus is neutral to typing at all, and many of its functions can be meaningfully applied to all type of arguments. The trivial example is the identity function
:id ≡ λ x . x
which simply returns whatever value it is applied to. Less trivial examples include parametric types like
list
A ''list'' is any set of items in a row. List or lists may also refer to:
People
* List (surname)
Organizations
* List College, an undergraduate division of the Jewish Theological Seminary of America
* SC Germania List, German rugby uni ...
s.
While polymorphism in general means that operations accept values of more than one type, the polymorphism used here is parametric. One finds the notation of ''type schemes'' in the literature, too, emphasizing the parametric nature of the polymorphism. Additionally, constants may be typed with (quantified) type variables. E.g.:
cons : forall a . a -> List a -> List a
nil : forall a . List a
id : forall a . a -> a
Polymorphic types can become monomorphic by consistent substitution of their variables. Examples of monomorphic ''instances'' are:
id' : String -> String
nil' : List Number
More generally, types are polymorphic when they contain type variables, while types without them are monomorphic.
Contrary to the type systems used for example in
Pascal (1970) or
C (1972), which only support monomorphic types, HM is designed with emphasis on parametric polymorphism. The successors of the languages mentioned, like
C++ (1985), focused on different types of polymorphism, namely
subtyping
In programming language theory, subtyping (also subtype polymorphism or inclusion polymorphism) is a form of type polymorphism in which a subtype is a datatype that is related to another datatype (the supertype) by some notion of substitutability, ...
in connection with
object-oriented programming
Object-oriented programming (OOP) is a programming paradigm based on the concept of " objects", which can contain data and code. The data is in the form of fields (often known as attributes or ''properties''), and the code is in the form of ...
and
overloading. While subtyping is incompatible with HM, a variant of systematic overloading is available in the HM-based type system of Haskell.
Let-polymorphism
When extending the type inference for the simply-typed lambda calculus towards polymorphism, one has to define when deriving an instance of a value is admissible. Ideally, this would be allowed with any use of a bound variable, as in:
(λ id . ... (id 3) ... (id "text") ... ) (λ x . x)
Unfortunately, type inference in
polymorphic lambda calculus is not decidable. Instead, HM provides a ''let-polymorphism'' of the form
let id = λ x . x
in ... (id 3) ... (id "text") ...
restricting the binding mechanism in an extension of the expression syntax. Only values bound in a let construct are subject to instantiation, i.e. are polymorphic, while the parameters in lambda-abstractions are treated as being monomorphic.
Overview
The remainder of this article proceeds as follows:
* The HM type system is defined. This is done by describing a deduction system that makes precise what expressions have what type, if any.
* From there, it works towards an implementation of the type inference method. After introducing a syntax-driven variant of the above deductive system, it sketches an efficient implementation (algorithm J), appealing mostly to the reader's metalogical intuition.
* Because it remains open whether algorithm J indeed realises the initial deduction system, a less efficient implementation (algorithm W), is introduced and its use in a proof is hinted.
* Finally, further topics related to the algorithm are discussed.
The same description of the deduction system is used throughout, even for the two algorithms, to make the various forms in which the HM method is presented directly comparable.
The Hindley–Milner type system
The type system can be formally described by
syntax rules that fix a language for the expressions, types, etc. The presentation here of such a syntax is not too formal, in that it is written down not to study the
surface grammar, but rather the
depth grammar, and leaves some syntactical details open. This form of presentation is usual. Building on this,
typing rule
In type theory, a typing rule is an inference rule that describes how a type system assigns a type to a syntactic construction. These rules may be applied by the type system to determine if a program is well-typed and what type expressions have. ...
s are used to define how expressions and types are related. As before, the form used is a bit liberal.
Syntax
The expressions to be typed are exactly those of the
lambda calculus
Lambda calculus (also written as ''λ''-calculus) is a formal system in mathematical logic for expressing computation based on function abstraction and application using variable binding and substitution. It is a universal model of computation t ...
extended with a let-expression as shown in the adjacent table. Parentheses can be used to disambiguate an expression. The application is left-binding and binds stronger than abstraction or the let-in construct.
Types are syntactically split into two groups, monotypes and polytypes.
[Polytypes are called "type schemes" in the original article.]
Monotypes
Monotypes always designate a particular type. Monotypes
are syntactically represented as
terms.
Examples of monotypes include type constants like
or
, and parametric types like
. The latter types are examples of ''applications'' of type functions, for example, from the set
,
where the superscript indicates the number of type parameters. The complete set of type functions
is arbitrary in HM,
[The parametric types were not present in the original paper on HM and are not needed to present the method. None of the inference rules below will take care or even note them. The same holds for the non-parametric "primitive types" in said paper. All the machinery for polymorphic type inference can be defined without them. They have been included here for sake of examples but also because the nature of HM is all about parametric types. This comes from the function type , hard-wired in the inference rules, below, which already has two parameters and has been presented here as only a special case.] except that it ''must'' contain at least
, the type of functions. It is often written in infix notation for convenience. For example, a function mapping integers to strings has type
. Again, parentheses can be used to disambiguate a type expression. The application binds stronger than the infix arrow, which is right-binding.
Type variables are admitted as monotypes. Monotypes are not to be confused with monomorphic types, which exclude variables and allow only ground terms.
Two monotypes are equal if they have identical terms.
Polytypes
''Polytypes'' (or ''type schemes'') are types containing variables bound by zero or more for-all quantifiers, e.g.
.
A function with polytype
can map ''any'' value of the same type to itself,
and the
identity function
Graph of the identity function on the real numbers
In mathematics, an identity function, also called an identity relation, identity map or identity transformation, is a function that always returns the value that was used as its argument, unc ...
is a value for this type.
As another example,
is the type of a function mapping all finite sets to integers. A function which returns the
cardinality
In mathematics, the cardinality of a set is a measure of the number of elements of the set. For example, the set A = \ contains 3 elements, and therefore A has a cardinality of 3. Beginning in the late 19th century, this concept was generalized ...
of a set would be a value of this type.
Quantifiers can only appear top level. For instance, a type
is excluded by the syntax of types. Also monotypes are included in the polytypes, thus a type has the general form
, where
is a monotype.
Equality of polytypes is up to reordering the quantification and renaming the quantified variables (
-conversion). Further, quantified variables not occurring in the monotype can be dropped.
Context and typing
To meaningfully bring together the still disjoint parts (syntax expressions and types) a third part is needed: context. Syntactically, a context is a list of pairs
, called
assignments,
assumptions or
bindings, each pair stating that value variable
has type
. All three parts combined give a ''typing judgment'' of the form
, stating that under assumptions
, the expression
has type
.
Free type variables
In a type
, the symbol
is the quantifier binding the type variables
in the monotype
. The variables
are called ''quantified'' and any occurrence of a quantified type variable in
is called ''bound'' and all unbound type variables in
are called ''free''. Additionally to the quantification
in polytypes, type variables can also be bound by occurring in the context, but with the inverse effect on the right hand side of the
. Such variables then behave like type constants there. Finally, a type variable may legally occur unbound in a typing, in which case they are implicitly all-quantified.
The presence of both bound and unbound type variables is a bit uncommon in programming languages. Often, all type variables are implicitly treated all-quantified. For instance, one does not have clauses with free variables in
Prolog
Prolog is a logic programming language associated with artificial intelligence and computational linguistics.
Prolog has its roots in first-order logic, a formal logic, and unlike many other programming languages, Prolog is intended primarily a ...
. Likewise in Haskell,
[Haskell provides the ScopedTypeVariables language extension allowing to bring all-quantified type variables into scope.] where all type variables implicitly occur quantified, i.e. a Haskell type
a -> a
means
here. Related and also very uncommon is the binding effect of the right hand side
of the assignments.
Typically, the mixture of both bound and unbound type variables originate from the use of free variables in an expression. The
constant function
In mathematics, a constant function is a function whose (output) value is the same for every input value. For example, the function is a constant function because the value of is 4 regardless of the input value (see image).
Basic properti ...
K =
provides an example. It has the monotype
. One can force polymorphism by
. Herein,
has the type
. The free monotype variable
originates from the type of the variable
bound in the surrounding scope.
has the type
. One could imagine the free type variable
in the type of
be bound by the
in the type of
. But such a scoping cannot be expressed in HM. Rather, the binding is realized by the context.
Type order
Polymorphism means that one and the same expression can have (perhaps infinitely) many types. But in this type system, these types are not completely unrelated, but rather orchestrated by the parametric polymorphism.
As an example, the identity
can have
as its type as well as
or
and many others, but not
. The most general type for this function is
, while the
others are more specific and can be derived from the general one by consistently
replacing another type for the ''type parameter'', i.e. the quantified
variable
. The counter-example fails because the
replacement is not consistent.
The consistent replacement can be made formal by applying a
substitution to the term of a type
, written
. As the example suggests, substitution is not only strongly related to an order, that expresses that a type is more or less special, but also with the all-quantification which allows the substitution to be applied.
Formally, in HM, a type
is more general than
, formally
, if some quantified variable in
is consistently substituted such that one gains
as shown in the side bar. This order is part of the type definition of the type system.
In our previous example, applying the substitution
would result in
.
While substituting a monomorphic (ground) type for a quantified variable is
straight forward, substituting a polytype has some pitfalls caused by the
presence of free variables. Most particularly, unbound variables must not be
replaced. They are treated as constants here. Additionally, quantifications can only occur top-level. Substituting a parametric type,
one has to lift its quantifiers. The table on the right makes the rule precise.
Alternatively, consider an equivalent notation for the polytypes without
quantifiers in which quantified variables are represented by a different set of
symbols. In such a notation, the specialization reduces to plain consistent
replacement of such variables.
The relation
is a
partial order
In mathematics, especially order theory, a partially ordered set (also poset) formalizes and generalizes the intuitive concept of an ordering, sequencing, or arrangement of the elements of a set. A poset consists of a set together with a binary ...
and
is its smallest element.
Principal type
While specialization of a type scheme is one use of the order, it plays a
crucial second role in the type system. Type inference with polymorphism
faces the challenge of summarizing all possible types an expression may have.
The order guarantees that such a summary exists as the most general type
of the expression.
Substitution in typings
The type order defined above can be extended to typings because the implied all-quantification of typings enables consistent replacement:
:
Contrary to the specialisation rule, this is not part of the definition, but like the implicit all-quantification rather a consequence of the type rules defined next.
Free type variables in a typing serve as placeholders for possible refinement. The binding effect of the environment to free type
variables on the right hand side of
that prohibits their substitution in the specialisation rule is again
that a replacement has to be consistent and would need to include the whole typing.
This article will discuss four different rule sets:
:#
declarative system
:#
syntactical system
:#
algorithm J
:#
algorithm W
Deductive system
The syntax of HM is carried forward to the syntax of the
inference rules
In the philosophy of logic, a rule of inference, inference rule or transformation rule is a logical form consisting of a function which takes premises, analyzes their syntax, and returns a conclusion (or conclusions). For example, the rule of ...
that form the body of the
formal system
A formal system is an abstract structure used for inferring theorems from axioms according to a set of rules. These rules, which are used for carrying out the inference of theorems from axioms, are the logical calculus of the formal system.
A for ...
, by using the typings as
judgments
Judgement (or US spelling judgment) is also known as '' adjudication'', which means the evaluation of evidence to make a decision. Judgement is also the ability to make considered decisions. The term has at least five distinct uses. Aristotle s ...
. Each of the rules define what conclusion could be drawn from what premises. Additionally to the judgments, some extra conditions introduced above might be used as premises, too.
A proof using the rules is a sequence of judgments such that all premises are listed before a conclusion. The examples below show a possible format of proofs. From left to right, each line shows the conclusion, the