I can close the ability to create an instance of variant type outside the containing module with a private
keyword.
module Ordinary : sig
type t = private X | Y
val x : t
end = struct
type t = X | Y
let x = X
end
I can't create instances of Ordinary.t
and the following example is uncompilable:
let f x = if x = Ordinary.X then 1 else 2
Error: Cannot create values of the private type Ordinary.t
But I can match Ordinary.t
and the following function works fine:
let f a = function
| Ordinary.X -> 1
| Ordinary.Y -> 2
For me, it is logically correct and I expect the same behavior from polymorphic variants. I created the analogical module for this case too.
module Polymorphic : sig
type t = private [`X | `Y]
val x : t
end = struct
type t = [`X | `Y]
let x = `X
end
But I can't match Polymorphic.t
. All my tries with error messages are shown below:
let g a =
match a with
| `X -> 1
| `Y -> 2
let x = g Polymorphic.x
let x = g Polymorphic.x ^^^^^^^^^^^^^
Error: This expression has type Polymorphic.t but an expression was expected of type [< `X | `Y ]
let x = match Polymorphic.x with
| `X -> 1
| `Y -> 2
| `X -> 1 ^^
Error: This pattern matches values of type [? `X ] but a pattern was expected which matches values of type Polymorphic.t
let x = match Polymorphic.x with
| Polymorphic.`X -> 1
| Polymorphic.`Y -> 2
| Polymorphic.`X ^
Error: Syntax error
let x =
let open Polymorphic in
match x with
| `X -> 1
| `Y -> 2
| `X -> 1 ^^
Error: This pattern matches values of type [? `X ] but a pattern was expected which matches values of type Polymorphic.t
Is it possible to match the private polymorphic variant type outside of the declaration container?
If it is - How? If it is not - Why?
The essence of private types is that they are private subtypes of a visible type. In particular values of the private type can be coerced with :>
to the visible type.
So, this works for me:
# match (Polymorphic.x :> [`X|`Y]) with
| `X -> 1
| `Y -> 2
;;
- : int = 1
For what it's worth, I think of a polymorphic variant value like `X
to be pervasive, like the number 1234. So `X
and `Y
aren't so much defined in Polymorphic
as referenced there. I.e., there is no special Polymorphic.(`X)
value that's different from the unqualified value `X
.
But there is a type Polymorphic.t
that's particular to the module. Values of this type can be coerced to [ `X | `Y ]
but not the other way around.
I hope my way of looking at this isn't too wrong :-) And I hope this is helpful.