Type inference

For example, consider the English language and terms that could fill in the blank in the phrase "sing _."

At best it might be metaphor; bending type rules is a feature of poetic language.

For example, we would interpret "to hang up the clothes line" as putting it into use, but "to hang up the leash" as putting it away, even though, in context, both "clothes line" and "leash" might refer the same rope, just at different times.

For instance, if the type system treats all numbers as the same, then a programmer who accidentally writes code where 4 is supposed to mean "4 seconds" but is interpreted as "4 meters" would have no warning of their mistake until it caused problems at runtime.

In fact, Russell's paradox sparked early versions of type theory.

There are several ways that a term can get its type: Especially in programming languages, there may not be much shared background knowledge available to the computer.

Some languages that include type inference include C23,[2] C++11,[3] C# (starting with version 3.0), Chapel, Clean, Crystal, D, F#,[4] FreeBASIC, Go, Haskell, Java (starting with version 10), Julia,[5] Kotlin,[6] ML, Nim, OCaml, Opa, Q#, RPython, Rust,[7] Scala,[8] Swift,[9] TypeScript,[10] Vala,[11] Dart,[12] and Visual Basic[13] (starting with version 9.0).

It revisits the prior inferences and uses the most general type from the outset: in this case floating-point.

This can however have detrimental implications, for instance using a floating-point from the outset can introduce precision issues that would have not been there with an integer type.

Frequently, however, degenerate type-inference algorithms are used that cannot backtrack and instead generate an error message in such a situation.

This behavior may be preferable as type inference may not always be neutral algorithmically, as illustrated by the prior floating-point precision issue.

Finally, a significant downside of complex type-inference algorithm is that the resulting type inference resolution is not going to be obvious to humans (notably because of the backtracking), which can be detrimental as code is primarily intended to be comprehensible to humans.

In complex forms of higher-order programming and polymorphism, it is not always possible for the compiler to infer as much, and type annotations are occasionally necessary for disambiguation.

[14] Some methods for type inference are based on constraint satisfaction[15] or satisfiability modulo theories.

The algorithms used by programs like compilers are equivalent to the informally structured reasoning above, but a bit more verbose and methodical.

First, we make fresh type variables for each individual term: Then we make fresh type variables for subexpressions built from these terms, constraining the type of the function being invoked accordingly: We also constrain the left and right sides of each equation to unify with each other: κ ~ [δ] and μ ~ ο.

Let us begin by substituting ο for μ and [δ] for κ: Substituting ζ for η, [ζ] for θ and λ, ι for ν, and [ι] for ξ and ο, all possible because a type constructor like · -> · is invertible in its arguments: Substituting ζ -> ι for ε and β -> [γ] -> [δ] for α, keeping the second constraint around so that we can recover α at the end: And, finally, substituting (ζ -> ι) for β as well as ζ for γ and ι for δ because a type constructor like [·] is invertible eliminates all the variables specific to the second constraint: No more substitutions are possible, and relabeling gives us map :: (a -> b) -> [a] -> [b], the same as we found without going into these details.

[citation needed] In 1969 J. Roger Hindley extended this work and proved that their algorithm always inferred the most general type.