问题
(This is an extension / distillation of Polymorphic variants and let%bind type error)
Consider the following code:
Version 1:
let x : [> `Error1 ] = (`Error1 : [> `Error1 ])
let y : [> `Error1 | `Error2 ] = x
Version 2:
let x : [> `Error1 ] = (`Error1 : [ `Error1 ])
let y : [> `Error1 | `Error2 ] = x
Version 1 typechecks, but version 2 fails (I'm compiling with 4.09.0):
File "test.ml", line 2, characters 33-34:
2 | let y : [> `Error1 | `Error2 ] = x
^
Error: This expression has type [ `Error1 ]
but an expression was expected of type [> `Error1 | `Error2 ]
The first variant type does not allow tag(s) `Error2
Note that this error occurs in the definition of y
, but the signature of x
is the same in both cases! How is it that y
can see inside the definition of x
? Is there more typechecking information about x
than its signature?
回答1:
In brief, explicit type annotations are not type signatures. In particular, in
let x : [> `Error1 ] = (`Error1 : [ `Error1 ])
the type of x
is [ `Error1 ]
.
The root of the issue is that unification type variables in explicit type annotations can be unified with concrete types.
A simpler instance of your problem is
let f: 'a -> 'a = fun x -> x + 1
Here, the 'a -> 'a
annotation is unified with the real type int->int
and thus this code typechecks. If you want to make the type variable 'a
universal, you need to be more explicit by adding an explicit universal quantification
let f: 'a. 'a -> 'a = fun x -> x + 1
Error: This definition has type int -> int which is less general than 'a. 'a -> 'a
The same phenomenon happens with your code with the implicit row variable:
let x : [> `Error1 ] = (`Error1 : [ `Error1 ])
This annotation does not guarantee that the type of x
is [> `Error1]
but only that it can be unified with [> `Error1]
. And since the type [ `Error1 ]
can be unified with [> `Error1 ]
, there is no reason to raise an error.
As before, if you want to avoid this issue, you need to be explicit about which variables are universally quantified in your annotation:
let x : 'row. ([> `Error1 ] as 'row) = (`Error1 : [ `Error1 ])
Error: This expression has type [ `Error1 ] but an expression was expected of type [> `Error1 ] The second variant type is bound to the universal type variable 'a, it cannot be closed
来源:https://stackoverflow.com/questions/62175970/polymorphic-variants-and-type-signatures