Spec-Zone.ru › OCaml
☰Язык OCaml
  • Язык OCaml
  • Расширения языка

Глава 12 Расширения языка

3 Приватные типы

  • 3.1 Приватные варианты и типы записей
  • 3.2 Приватные сокращения типов
  • 3.3 Приватные строковые типы

Объявления приватных типов в сигнатурах модулей вида type t = private ... позволяют библиотекам раскрывать клиентам библиотеки некоторые, но не все аспекты реализации типа. В этом отношении они занимают промежуточное положение между объявлениями абстрактных типов, не раскрывающими никаких сведений о реализации типа, и определениями типов данных и сокращениями типов, полностью раскрывающими реализацию типа. Существует три разновидности объявлений приватных типов: для вариантов и типов записей (раздел 12.3.1), для сокращений типов (раздел 12.3.2) и для строковых типов (раздел 12.3.3).

3.1 Приватные варианты и типы записей

(Добавлено в Objective Caml 3.07)

type-representation ::= ...
∣ = private [ | ] constr-decl { | constr-decl }
∣ = private record-decl

Значения варианта или типа записи, объявленного как private, можно обычным образом разбирать в сопоставлении с образцом или обращаться к ним с помощью записи expr . field. Однако значения этих типов нельзя создавать напрямую с помощью применения конструктора или создания записи. Кроме того, присваивание полю изменяемой приватной записи не допускается.

Приватные типы обычно используются в экспортируемой сигнатуре модуля, чтобы гарантировать, что значения приватного типа всегда создаются с помощью функций, предоставленных модулем, при этом сопоставление с образцом остается доступным за пределами определяющего модуля. Например:

module M : sig
  type t = private A | B of int
  val a : t
  val b : int -> t
end = struct
  type t = A | B of int
  let a = A
  let b n = assert (n > 0); B n
end

Здесь объявление private гарантирует, что в любом значении типа M.t аргумент конструктора B всегда является положительным целым числом.

С точки зрения дисперсии параметров с приватными типами обращаются так же, как с абстрактными типами. То есть, если у приватного типа есть параметры, их дисперсия задается явно с помощью префикса «+» или «-» перед параметром; в противном случае она инвариантна.

3.2 Приватные сокращения типов

(Добавлено в Objective Caml 3.11)

type-equation ::= ...
∣ = private typexpr

В отличие от обычного сокращения типа, приватное сокращение объявляет тип, отличный от типа его реализации typexpr. Однако приведение этого типа к typexpr разрешено. Кроме того, компилятор «знает» тип реализации и может использовать это знание для оптимизаций, учитывающих типы.

В следующем примере с помощью приватного сокращения типа определяется модуль неотрицательных целых чисел:

module N : sig
  type t = private int
  val of_int: int -> t
  val to_int: t -> int
end = struct
  type t = int
  let of_int n = assert (n >= 0); n
  let to_int n = n
end

Тип N.t несовместим с типом int, благодаря чему неотрицательные целые числа не смешиваются с обычными целыми числами. Однако, если x имеет тип N.t, приведение (x :> int) допустимо и возвращает лежащее в основе целое число, как и N.to_int x. Поддерживаются также глубокие приведения: если l имеет тип N.t list, приведение (l :> int list) возвращает список лежащих в основе целых чисел, как и List.map N.to_int l, но без копирования списка l.

Обратите внимание: приведение ( expr :> typexpr ) на самом деле является сокращенной формой и работает с приватными сокращениями только в том случае, если типы expr и typexpr не содержат переменных типа. Если они их содержат, необходимо использовать полную форму ( expr : typexpr1 :> typexpr2 ), где typexpr1 — ожидаемый тип expr. В приведенных выше примерах это будут (x : N.t :> int) и (l : N.t list :> int list).

3.3 Приватные строковые типы

(Добавлено в Objective Caml 3.09)

type-equation ::= ...
∣ = private typexpr

Приватные строковые типы — это сокращения типов, в которых часть структуры типа остается абстрактной. В частности, typexpr в приведенном выше примере должен обозначать либо тип объекта, либо полиморфный вариантный тип, допускающий некоторую степень уточнения. Если приватное объявление используется в интерфейсе, соответствующая реализация может предоставить либо конкретный экземпляр, либо уточненный приватный тип.

module M : sig type c = private < x : int; .. > val o : c end =
struct
  class c = object method x = 3 method y = 2 end
  let o = new c
end

Это объявление не только скрывает метод y, но и делает тип c несовместимым с любым другим замкнутым типом объекта, то есть только o будет иметь тип c. В этом отношении он ведет себя подобно приватным типам записей. Однако приватные строковые типы более гибки в отношении постепенного уточнения. Эта возможность может использоваться совместно с функторами.

module F(X : sig type c = private < x : int; .. > end) =
struct
  let get_x (o : X.c) = o#x
end
module G(X : sig type c = private < x : int; y : int; .. > end) =
struct
  include F(X)
  let get_y (o : X.c) = o#y
end

Полиморфный вариантный тип [t], например

type t = [ `A of int | `B of bool ]

можно уточнить двумя способами. Определение [u] может добавить новые поля в [t], а объявление

type u = private [> t]

оставит эти новые поля абстрактными. Значения типа [u] можно создавать с помощью известных вариантов [t], но при любом сопоставлении с образцом потребуется вариант по умолчанию для обработки возможных дополнительных полей. И наоборот, объявление [u] может ограничить поля [t] посредством абстракции: объявление

type v = private [< t > `A]

соответствует приватным вариантным типам. Нельзя создать значение приватного типа [v], кроме как с помощью явно перечисленных присутствующих конструкторов, в данном примере — (`A n); однако при сопоставлении с образцом для [v] следует исходить из того, что могут присутствовать любые конструкторы типа [t].

Как и для абстрактных типов, дисперсия параметров типа не выводится автоматически и должна задаваться явно.

« Рекурсивные модулиЛокально абстрактные типы »
Авторское право © 2026 Institut National de Recherche en Informatique et en Automatique

© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/privatetypes.html

Spec-Zone.ru

Настройки Оффлайн Что нового Помощь О нас
Spec-Zone .ru
спецификации, руководства, описания, API