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

Ограничения

Если правая часть подстановки типа модуля или локальной подстановки типа модуля не является 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)
« Восстановление типа модуляТип-уровневые псевдонимы модулей »
Авторское право © 2024 Institut National de Recherche en Informatique et en Automatique

© 1995-2024 INRIA.
https://ocaml.org/manual/5.2/signaturesubstitution.html

Spec-Zone.ru

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