Как сделать значение типа, который определен с модулем в OCaml? - PullRequest
0 голосов
/ 08 января 2020

TL; DR - В OCaml как вызывать тип выглядит как type 'elt set = (module BatSet.S with type elt = 'elt) и как сделать значение этого типа?

В настоящее время я читаю код в протокол Tezos [*], и я увидел следующий код:

module type Boxed_set = sig
  type elt
  val elt_ty : elt comparable_ty
  module OPS : S.SET with type elt = elt
  val boxed : OPS.t
  val size : int
end

type 'elt set = (module Boxed_set with type elt = 'elt)

Я никогда не слышал о синтаксисе типа type a = (module B). Поэтому я открываю интерпретатор OCaml верхнего уровня и воспроизводю аналогичное использование, используя модуль battery . Следующий код - это журнал того, что я воспроизвел.

$ ocaml
        OCaml version 4.07.1

# #use "topfind";;
- : unit = ()
Findlib has been successfully loaded. Additional directives:
  #require "package";;      to load a package
  #list;;                   to list the available packages
  #camlp4o;;                to load camlp4 (standard syntax)
  #camlp4r;;                to load camlp4 (revised syntax)
  #predicates "p,q,...";;   to set these predicates
  Topfind.reset();;         to force that packages will be reloaded
  #thread;;                 to enable threads

- : unit = ()

# #require "batteries";;
[...]: loaded

# type 'elt set = (module BatSet.S with type elt = 'elt);;
type 'elt set = (module BatSet.S with type elt = 'elt)

Это странное определение типа действительно работает, но я застрял здесь. Как сам модуль может быть типом? Как сделать значение типа 'elt set как let v : int set = (...)? Есть ли какое-либо ключевое слово для вызова таких типов?

[*] https://gitlab.com/tezos/tezos/blob/master/src/proto_alpha/lib_protocol/script_typed_ir.ml, Commit-Ha sh: 86b5227f7efd8aa78fcc427776920480c6c0e780

Ответы [ 2 ]

5 голосов
/ 08 января 2020

Это тип модуля первого класса с ограничением: https://caml.inria.fr/pub/docs/manual-ocaml/manual028.html.

Этот тип может использоваться для упаковки модуля внутри значения:

let int_set = ((module BatSet.Make(Int)): int set);;

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

let unique_sorted (type a) ((module MySet): a set) list =
  let set = List.fold_left (fun set x -> MySet.add x set) MySet.empty list in
  MySet.elements set
let test = assert( unique_sorted int_set [4;0;1;2;2] = [0;1;2;4] )
2 голосов
/ 08 января 2020

Тип типа (module M) является типом модуля первого класса.

Вы можете создать значение такого типа, просто определив модуль с правильным типом.

Вот простой пример, который я использовал для проверки этого:

# module type B = sig type elt end;;
module type B = sig type elt end
# type 'elt b = (module B with type elt = 'elt);;
type 'elt b = (module B with type elt = 'elt)
# module X = struct type elt = int end;;
module X : sig type elt = int end
# (module X : B with type elt = int);;
- : (module B with type elt = int) = <module>

Эта последняя строка показывает module X, обработанный как значение (первоклассный модуль).

Теперь, действительно, это значение имеет тип int b:

# ((module X : B with type elt = int) : int b);;
- : (module B with type elt = int) = <module>
...