It's not true that polymorphic variants are always less efficient. Using Martin's example:
type base = [`String of string | `Int of int] type t1 = [base | `Bool of bool | `List of t1 list] type t2 = [base | `Other] let simplify (x:t1):t2 = match x with | #base as b -> b | `Bool _ | `List _ -> `Other
To do this with standard variants requires two distinct types and a complete recoding, with polymorphic variants the base case is physically invariant. This feature really comes into its own when using open recursion for term rewriting:
type leaf = [`String of string | `Int of int] type 'b base = [leaf | `List of 'b list] type t1 = [t1 base | `Bool of bool ] type t2 = [t2 base | `Other] let rec simplify (x:t1):t2 = match x with | #leaf as x -> x | `List t -> `List (List.map simplify t) | `Bool _ -> `Other
and the advantages are even greater when the rewriting functions are also factored with open recursion.
Unfortunately Ocaml's Hindley-Milner type inference is not strong enough to do this kind of thing without explicit typing, which requires careful factorisation of the types, which in turn makes proto-typing difficult. Additionally, explicit coercions are sometimes required.
The big downside of this technique is that for terms with multiple parameters, one soon ends up with a rather confusing combinatorial explosion of types, and in the end it is easier to give up on static enforcement and use a kitchen sink type with wildcards and exceptions (i.e. dynamic typing).
exn.