Глава 12. Расширения языка
7 Подстановка внутри сигнатуры
7.1 Разрушающие подстановки
(Добавлены в OCaml 3.12, обобщены в версии 4.06)
|
«Разрушающая» подстановка (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)
|
Локальные подстановки работают как разрушающие подстановки (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)
|
Подстановка типа модуля по существу работает как подстановка типа. Она позволяет уточнить абстрактный тип модуля в сигнатуре, заменив его конкретным типом модуля,
# 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)
© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/signaturesubstitution.html