This is a consequence of the value restriction, as described in the following FAQ item:
A function obtained through partial application is not polymorphic enough
The more common case to get a ``not polymorphic enough'' definition is when defining a function via partial application of a general polymorphic function. In Caml polymorphism is introduced only through the “let” construct, and results from application are weakly polymorph; hence the function resulting from the application is not polymorph. In this case, you recover a fully polymorphic definition by clearly exhibiting the functionality to the type-checker : define the function with an explicit functional abstraction, that is, add a function construct or an extra parameter (this rewriting is known as eta-expansion):
# let map_id = List.map (function x -> x) (* Result is weakly polymorphic *) val map_id : '_a list -> '_a list = <fun> # map_id [1;2] - : int list = [1;2] # map_id (* No longer polymorphic *) - : int list -> int list = <fun> # let map_id' l = List.map (function x -> x) l val map_id' : 'a list -> 'a list = <fun> # map_id' [1;2] - : int list = [1;2] # map_id' (* Still fully polymorphic *) - : 'a list -> 'a list = <fun>
The two definitions are semantically equivalent, and the new one can be assigned a polymorphic type scheme, since it is no more a function application.
See also this discussion about what the _
in '_a
indicates -- weak, non-polymorphic type variables.