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

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

7 Подстановка внутри сигнатуры

  • 7.1 Разрушающие подстановки
  • 7.2 Объявления локальных подстановок
  • 7.3 Подстановки типов модулей

7.1 Разрушающие подстановки

(Добавлены в OCaml 3.12, обобщены в версии 4.06)

mod-constraint ::= ...
∣ type [type-params] typeconstr-name := typexpr
∣ module module-path := extended-module-path

«Разрушающая» подстановка (with ... := ...) по существу работает как обычные ограничения сигнатуры (with ... = ...), но дополнительно удаляет из сигнатуры переопределённый тип или модуль.

До OCaml 4.06 существовал ряд ограничений: удалять можно было только типы и модули на самом внешнем уровне (но не внутри подмодулей), а в случае with type определение должно было ссылаться на другой конструктор типа с теми же параметрами типа.

Естественное применение разрушающей подстановки — объединение двух сигнатур с общим именем типа.

module type Printable = sig
  type t
  val print : Format.formatter -> t -> unit
end
module type Comparable = sig
  type t
  val compare : t -> t -> int
end
module type PrintableComparable = sig
  include Printable
  include Comparable with type t := t
end

С её помощью также можно полностью удалить поле:

module type S = Comparable with type t := int

module type S = sig val compare : int -> int -> int end

или переименовать его:

module type S = sig
  type u
  include Comparable with type t := u
end

module type S = sig type u val compare : u -> u -> int end

Обратите внимание: можно также удалять манифестные типы, подставляя вместо них тот же тип.

module type ComparableInt = Comparable with type t = int ;;

module type ComparableInt = sig type t = int val compare : t -> t -> int end
module type CompareInt = ComparableInt with type t := int

module type CompareInt = sig val compare : int -> int -> int end

7.2 Объявления локальных подстановок

(Добавлены в OCaml 4.08, подстановки типов модулей — в версии 4.13)

specification ::= ...
∣ type type-subst { and type-subst }
∣ module module-name := extended-module-path
∣ module type module-name := module-type
type-subst ::= [type-params] typeconstr-name := typexpr { type-constraint }

Локальные подстановки работают как разрушающие подстановки (with ... := ...), но применяются не ко всей сигнатуре постфактум: они вводятся при описании сигнатуры и действуют на все последующие элементы.

Это позволяет удобно задавать локальные имена типов и модулей при определении сигнатуры:

module type S = sig
  type t
  module Sub : sig
    type outer := t
    type t
    val to_outer : t -> outer
  end
end

module type S =
  sig type t module Sub : sig type t val to_outer : t -> t/2 end end

Обратите внимание: в отличие от объявлений типов, объявления подстановок типов не являются рекурсивными, поэтому подстановки вроде следующей отвергаются:

# module type S = sig
    type 'a poly_list := [ `Cons of 'a * 'a poly_list | `Nil ]
  end ;;

Error: Unbound type constructor poly_list

Локальные подстановки также можно использовать, чтобы задать локальное имя для типа или типа модуля, введённого применением функтора:

# module type F = sig
    type set := Set.Make(Int).t

    module type Type = sig type t end
    module Nest : Type -> sig module type T = Type end

    module type T := Nest(Int).T

    val set: set
    val m : (module T)
  end;;

module type F =
  sig
    module type Type = sig type t end
    module Nest : Type -> sig module type T = Type end
    val set : Set.Make(Int).t
    val m : (module Nest(Int).T)
  end

На локальные подстановки типов модулей распространяются те же ограничения, что и на подстановки типов модулей; см. раздел 12.7.3.

7.3 Подстановки типов модулей

(Добавлены в OCaml 4.13)

mod-constraint ::= ...
∣ module type modtype-path = module-type
∣ module type modtype-path := module-type

Подстановка типа модуля по существу работает как подстановка типа. Она позволяет уточнить абстрактный тип модуля в сигнатуре, заменив его конкретным типом модуля,

# module type ENDO = sig
    module type T
    module F: T -> T
  end
  module Endo(X: sig module type T end): ENDO with module type T = X.T =
  struct
      module type T = X.T
      module F(X:T) = X
   end;;

module type ENDO = sig module type T module F : T -> T end
module Endo :
  (X : sig module type T end) ->
    sig module type T = X.T module F : T -> T end

Можно также заменить конкретный тип модуля эквивалентным ему типом модуля.

module type A = sig
  type x
  module type R = sig
    type a = A of x
    type b
  end
end
module type S = sig
  type a = A of int
  type b
end
module type B = A with type x = int and module type R = S

Однако такие подстановки никогда не требуются.

Разрушающая подстановка типа модуля удаляет подстановку типа модуля из сигнатуры

# module type ENDO' = ENDO with module type T := ENDO;;

module type ENDO' = sig module F : ENDO -> ENDO end

Ограничения

Если правая часть подстановки типа модуля или локальной подстановки типа модуля не является modtype-path, то разрушающая подстановка допустима только в том случае, если левая часть подстановки нигде не используется в исходном типе модуля как тип модуля первого класса.

module type T = sig module type S val x: (module S) end
module type Error = T with module type S := sig end

Error: This with constraint S := sig end makes a packed module ill-formed.
       (see manual section 12.7.3)
module type T = sig module type S := sig end val x: (module S) end

Error: The module type S is not a valid type for a packed module:
       it is defined as a local substitution (temporary name)
       for an anonymous module type. (see manual section 12.7.3)
« Восстановление типа модуляПсевдонимы модулей на уровне типов »
Авторские права © 2026 Национальный институт исследований в области информатики и автоматики

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

Spec-Zone.ru

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