Value restriction
also: relaxed value restriction, weak type variable, _weak
The rule that only syntactic values have their type variables generalized in a let. An application such as List.map f is not a value, so its type variables stay weak, fixed by the first use. OCaml relaxes the rule for type variables that occur only covariantly.
Without the restriction, mutable state breaks the type system. If ref [] had type 'a list ref for every 'a, one use could store an int in it and another read a string out of it. The restriction stops that by refusing to generalize the result of any computation, since a computation might have allocated state.
A value is a constant, a variable, a function, or a constructor applied to values. Anything else is an application.
let r = ref []let id_list = List.map (fun x -> x)let id_list' l = List.map (fun x -> x) llet empty = List.rev []
What ocamlc -i infers, OCaml 5.5.1.
val r : '_weak1 list refval id_list : '_weak2 list -> '_weak2 listval id_list' : 'a list -> 'a listval empty : 'a list
The fix for id_list is eta-expansion: adding the parameter back turns the application into a function, which is a value. The last line is the relaxation. 'a appears in empty's type only covariantly, as the element type of a list it returns, and a covariant variable can be generalized safely even for the result of a computation, because no one can store into it through that type.
A weak variable is not an error by itself. It becomes fixed at its first use, and it is an error only if the compilation unit ends with it still unfixed and exported.
see also
- Polymorphic variantA variant whose constructors, called tags and written with a backquote, exist independently of any type declaration. Their types are sets of tags with bounds: [> `A] means at least `A, [< `A | `B] at most those two, and unification works out unions and intersections of those sets.
- Phantom typeA type parameter that appears in a type's signature but in none of its fields, used purely to keep two otherwise identical representations from being mixed up. Unlike a GADT it adds no information at pattern-match time: it constrains what the caller may do, not what the compiler can learn.
- LensA first-class pair of a getter and a setter for one part of a structure, with laws that make them agree: you get back what you set, setting what you got changes nothing, and a second set overwrites the first. Lenses compose, so a path through nested records is one value.
referenced by
further reading
- A. K. Wright, “Simple imperative polymorphism”, LISP and Symbolic Computation 8 (1995).
- J. Garrigue, “Relaxing the value restriction”, FLOPS (2004).