Skip to content

Commit f5ec3a2

Browse files
jpaciknathanielc
authored andcommitted
docs: update type inference docs
1 parent ec2765e commit f5ec3a2

File tree

2 files changed

+121
-175
lines changed

2 files changed

+121
-175
lines changed

docs/TypeInference.md

Lines changed: 121 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
1+
### Type Inference in Flux
2+
--------------------------
3+
4+
Flux is a strongly and statically typed language supporting parametric polymorphism.
5+
Flux does not require explicit type annotions but rather infers the most general type of an expression.
6+
7+
#### Key Concepts
8+
9+
1. Monotypes
10+
11+
Monotypes are non-parameterized types.
12+
Examples include `int`, `string`, `boolean`, `(x: int) => int`, etc.
13+
14+
2. Polytypes
15+
16+
Polytypes are parameterized types sometimes referred to as type schemes in other literature.
17+
Parameters are type variables that can be substituted with any monotype.
18+
The following is a polytype with a single parameter `T`
19+
20+
(x: T) => T
21+
22+
3. Constraints
23+
24+
Type inference generates constraints that are later solved in order to determine the type of every expression in a flux program.
25+
Type inference generates two types of constraints - equality constraints and kind constraints.
26+
An equality constraint asserts that two types are equal.
27+
A kind constraint is used for implementing ad hoc polymorphism.
28+
It asserts that a type is one of a finite set of types.
29+
30+
4. Substitution
31+
32+
A substitution is a map.
33+
It maps type variables to monotypes.
34+
35+
5. Unification
36+
37+
Unification is the process of solving type constraints.
38+
Concretely unification is the process of solving for the type variables in a set of type constraints.
39+
The output of unification is a substitution.
40+
41+
6. Type Environment
42+
43+
A type environment maps program identifiers to their corresponding polytypes.
44+
45+
7. Generalization
46+
47+
Generalization is the process of converting a monotype into a polytype.
48+
See https://en.wikipedia.org/wiki/Hindley%E2%80%93Milner_type_system#Let-polymorphism_2.
49+
50+
8. Specialization
51+
52+
Specialization is the process of converting a polytype into a monotype.
53+
The monotype returned has new fresh type variables with respect to the current type environment.
54+
Specialization and generalization are used for implementing parametric polymorphism
55+
56+
#### Algorithm
57+
58+
The type inference algorithm that Flux uses is based on Wand's algorithm.
59+
It operates in two phases.
60+
First it generates a series of type constraints for a given expression.
61+
Then it solves those constraints using a process called unification.
62+
63+
Example:
64+
```
65+
f = (a, b) => a + b
66+
x = f(a: 0, b: 1)
67+
```
68+
69+
The algorithm will generate the following constraints for the function expression:
70+
71+
typeof(a) = typeof(a + b)
72+
typeof(b) = typeof(a + b)
73+
typeof(a) in [int, float, string]
74+
typeof(b) in [int, float, string]
75+
76+
Note the first two constraints are equality constraints whereas the latter two constraints are kind constraints.
77+
After unification we've inferred a monotype for the function expression.
78+
We then generalize this monotype and associate `f` with the resulting polytype in the type environment.
79+
80+
The algorithm then generates the following constraints for the call expression:
81+
82+
typeof(f) = (a: int, b: int) => t0
83+
typeof(f) = instantiate(environment(f))
84+
85+
The algorithm continues in the same way, generalizing the inferred type for the call expression and adding a new mapping for `x` in the type environment.
86+
87+
#### Polymorphism
88+
89+
Flux supports the following types of polymorphism.
90+
91+
##### Parametric Polymorphism
92+
93+
Parametric polymorphism is the notion that a function can be applied uniformly to arguments of any type.
94+
The identity function `(x) => x` is one such example of a function that can be applied to any type.
95+
96+
##### Record Polymorphism
97+
98+
Record polymorphism is the notion that a function can be applied to records of different types so long as they contain the necessary properties.
99+
The necessary properties of a record are determined by the use of a record.
100+
For example, the following function asserts that `r` must be a record having a label `a`.
101+
102+
f = (r) => r.a
103+
104+
Record polymorphism allows for one to pass `f` any record so long as it has a label `a`.
105+
The following records are all valid inputs to `f`.
106+
107+
{a: 0}
108+
{a: "string", b: 1}
109+
{c: "string", a: 1.1}
110+
111+
`{b: 0, c: 1}` however is not a valid input to `f` and the flux type checker will catch any cases where such a type is passed to `f`.
112+
113+
##### Ad hoc Polymorphism
114+
115+
Ad hoc polymorphism is the notion that a function can be applied to a finite set of types, with different behavior depending on the type.
116+
For example the `add` function does not support all types.
117+
118+
add = (a, b) => a + b
119+
120+
It supports integers, floating point numbers, and even strings as `+` represents concatenation for string types.
121+
However boolean types are not supported and the flux type checker will catch any cases where unsupported types such as booleans are passed to `add`.

semantic/type_inference.md

Lines changed: 0 additions & 175 deletions
This file was deleted.

0 commit comments

Comments
 (0)