Это неправда, что полиморфные варианты всегда менее эффективны.Используя пример Мартина:
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
Чтобы сделать это со стандартными вариантами, требуется два различных типа и полное перекодирование, при полиморфных вариантах базовый случай является физически инвариантным.Эта функция действительно вступает в свои права при использовании открытой рекурсии для переписывания терминов:
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
, и преимущества еще больше, когда функции перезаписи также учитывают открытую рекурсию.
К сожалению, Хиндли из Окамла- Вывод типа Миллера недостаточно силен, чтобы делать подобные вещи без явной типизации, что требует тщательной факторизации типов, что, в свою очередь, затрудняет прототипирование.Кроме того, иногда требуются явные приведения.
Большим недостатком этого метода является то, что для терминов с несколькими параметрами вскоре возникает довольно запутанный комбинаторный взрыв типов, и в конце концов его легче датьнад статическим применением и используйте тип кухонной раковины с подстановочными знаками и исключениями (например, динамическая типизация).