Как сделать полиморфные варианты Ocaml приватными
Я хотел бы переключить некоторые из моих типов на использование полиморфных вариантов Ocaml, учитывая их с открытой рекурсией, сохраняя при этом соблюдение моих существующих частных неполиморфных типов, а также проверку исчерпывающей информации о совпадениях с образцами.
Мой продукт - это компилятор, поэтому набор типов изменяется с помощью различных алгоритмов, в настоящее время я должен включить все конструкторы, которые не должны встречаться, так как они должны быть "выданы как ложные".
Я должен добавить, что раньше использовал полиморфные варианты, но переключился на обычные, потому что вывод типов не очень хорошо работает с полиморфными вариантами: сообщения об ошибках трудно читать, и они ошибочны гораздо больше, чем обычные неправильные выводы, требующие много больше аннотаций типа на параметры, чтобы сохранить здравомыслие. Проблема в том, что без них принудительное применение частными конструкторами является сильным, а принудительное применение клиентских алгоритмов - слабым.
Я не совсем уверен, возможно ли или целесообразно ли объединять "специальные" подмножества конструкторов с конфиденциальностью. Любые предложения относительно того, насколько это практично?
РЕДАКТИРОВАТЬ: простые примеры типов:
(* open *)
type 'a x' = [`A | `B of 'a]
(* closed *)
type x = private 'u x' as 'u
(* open extension *)
type 'a y' = ['a x' | `C of 'a]
(* closed extension *)
type y = private 'u y' as 'u
let mkA () = `A
let mkB' (a:'a x') = `B a
(* how to do this? *)
let mkB (a:x) = mkB' (a :> 'a x')
При открытой рекурсии функции конструктора должны следовать шаблону открытых / закрытых типов. Клиент только увидит закрытые версии. Это означает, что в отличие от моей нынешней системы, где достаточно одной функции конструктора, мне теперь нужна одна для каждого закрытого типа, для каждого типа, в котором содержится конструктор.
Даже если я смогу понять, как это сделать, что довольно сложно, если вы скажете 6 взаимозависимых типов, ВСЕ из которых используют открытую рекурсию, что приводит к экспоненциальному взрыву возможных комбинаций, не ясно, является ли это преимуществом по сравнению с просто принимать проверки времени выполнения. У меня заняло около 2 часов, чтобы добавить новый конструктор, потому что каждое сопоставление с образцом терпит неудачу с ошибкой исчерпанности и должно быть исправлено... даже если новый конструктор не используется на этом этапе компиляции.'
1 ответ
Приватный полиморфный вариант интересен только с модулем и интерфейсами. Они довольно просты в модуле, но приватны снаружи благодаря интерфейсу. Если за пределами модуля вы хотите иметь доступ к общедоступному представительству, вам нужно предоставить функцию, которая сделает это:
module M : sig
(* open *)
type 'a x' = [`A | `B of 'a]
(* closed *)
type x = private 'u x' as 'u
val f: x -> x x'
end = struct
type 'a x' = [`A | `B of 'a]
type x = 'u x' as 'u
let f a = a
end
Еще один способ сделать это - немного изменить свой тип, сделав приватным только главный конструктор:
(* open *)
type 'a x' = [`A | `B of 'a]
(* closed *)
type x = 'u x' as 'u
(* private *)
type px = private x
let f (a: px) = (a :> x)