10.7 Замена внутри подписи
10.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
10.7.2 Локальные объявления замены
(Введено в OCaml 4.08)
|
Локальные замены ведут себя как деструктивные замены (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/1 -> 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 10.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 :
functor (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
Если правая часть замены не является путём, то деструктивная замена допустима только если левая часть замены никогда не используется в качестве типа первого класса модуля в исходном типе модуля.
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.
© 1995-2022 INRIA.
https://v2.ocaml.org/releases/4.14/htmlman/signaturesubstitution.html