Как сопоставить частный полиморфный вариантный тип вне содержащего модуля?

Я могу закрыть возможность создания экземпляра вариантного типа вне содержащего модуля с помощью private ключевое слово.

module Ordinary : sig
  type t = private X | Y
  val x : t
end = struct 
  type t = X | Y 
  let x = X
end

Я не могу создавать экземпляры Ordinary.t и следующий пример не компилируется:

let f x = if x = Ordinary.X then 1 else 2

Ошибка: не удается создать значения частного типа Ordinary.t

Но я могу соответствовать Ordinary.t и следующая функция работает нормально:

let f a = function
  | Ordinary.X -> 1
  | Ordinary.Y -> 2

Для меня это логически правильно, и я ожидаю такого же поведения от полиморфных вариантов. Аналогичный модуль я создал и для этого случая.

module Polymorphic : sig
  type t = private [`X | `Y]
  val x : t
end = struct 
  type t = [`X | `Y]
  let x = `X
end

Но я не могу соответствовать Polymorphic.t. Все мои попытки с сообщениями об ошибках показаны ниже:

let g a = 
  match a with
  | `X -> 1 
  | `Y -> 2
    
let x = g Polymorphic.x
let x = g Polymorphic.x
          ^^^^^^^^^^^^^

Ошибка: это выражение имеет тип Polymorphic.t, но ожидалось выражение типа [<`X | `Y]

let x = match Polymorphic.x with
  | `X -> 1
  | `Y -> 2 
| `X -> 1
  ^^

Ошибка: этот шаблон соответствует значениям типа [? `X ], но ожидался шаблон, который соответствует значениям типа Polymorphic.t

let x = match Polymorphic.x with
  | Polymorphic.`X -> 1
  | Polymorphic.`Y -> 2 
| Polymorphic.`X
              ^

Ошибка: синтаксическая ошибка

let x = 
  let open Polymorphic in
  match x with
  | `X -> 1
  | `Y -> 2
| `X -> 1
  ^^

Ошибка: этот шаблон соответствует значениям типа [? `X ], но ожидался шаблон, который соответствует значениям типа Polymorphic.t

Можно ли сопоставить частный полиморфный вариантный тип вне контейнера объявлений?
Если это так - как? Если нет - почему?

1 ответ

Решение

Суть частных типов в том, что они являются частными подтипами видимого типа. В частности, значения частного типа могут быть приведены с помощью:> к видимому типу.

Итак, это работает для меня:

# match (Polymorphic.x :> [`X|`Y]) with
  | `X -> 1
  | `Y -> 2
  ;;
- : int = 1

Как бы то ни было, я думаю о значении полиморфного варианта, например `X быть распространенным, как число 1234. Итак `X а также `Y не так сильно определены в Polymorphicкак указано там. Т.е. нет особенногоPolymorphic.(`X) значение, отличное от неквалифицированного значения `X.

Но есть тип Polymorphic.tэто относится к модулю. Значения этого типа можно принуждать к[ `X | `Y ] но не наоборот.

Я надеюсь, что мой взгляд на это не слишком ошибочен:-) И я надеюсь, что это полезно.

Другие вопросы по тегам