Spec-Zone.ru › OCaml 5.0

12.7 Замена в сигнатуре

  • 12.7.1 Деструктивные замены
  • 12.7.2 Локальные объявления замены
  • 12.7.3 Замены типов модулей

12.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

12.7.2 Локальные объявления замены

(Введено в OCaml 4.08)

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/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

12.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 :
  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/5.0/htmlman/signaturesubstitution.html

Spec-Zone.ru

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