Spec-Zone.ru › OCaml 5.0

12.4 Локально абстрактные типы

(Введены в OCaml 3.12, короткий синтаксис добавлен в 4.03)

parameter ::= ...
∣ ( type { typeconstr-name }+ )

Выражение fun ( type typeconstr-name ) -> expr вводит конструктор типа с именем typeconstr-name, который считается абстрактным в области подвыражения, но затем заменяется новой свободной переменной типа. Обратите внимание, что, вопреки тому, что может подразумевать синтаксис, выражение fun ( type typeconstr-name ) -> expr само по себе не приостанавливает вычисление expr, как это было бы с обычным абстрагированием. Синтаксис был выбран для удобства использования в контексте объявлений функций, где он обычно применяется. Возможна свободная комбинация обычных параметров функции с псевдопараметрами типа, как в:

let f = fun (type t) (foo : t list) -> …

и даже использование альтернативного синтаксиса для объявления функций:

let f (type t) (foo : t list) = …

Если необходимо ввести несколько локально абстрактных типов, можно использовать синтаксис fun ( type typeconstr-name1 … typeconstr-namen ) -> expr как синтаксический сахар для fun ( type typeconstr-name1 ) -> … -> fun ( type typeconstr-namen ) -> expr. Например,

let f = fun (type t u v) -> fun (foo : (t * u * v) list) -> …
let f' (type t u v) (foo : (t * u * v) list) = …

Это конструкция полезна, потому что введенные ею конструкторы типов могут использоваться в местах, где переменная типа не разрешена. Например, можно использовать её для определения исключения в локальном модуле внутри полиморфной функции.

let f (type t) () =
  let module M = struct exception E of t end in
  (fun x -> M.E x), (function M.E x -> Some x | _ -> None)

Вот еще один пример:

let sort_uniq (type s) (cmp : s -> s -> int) =
  let module S = Set.Make(struct type t = s let compare = cmp end) in
  fun l ->
    S.elements (List.fold_right S.add l S.empty)

Это также очень полезно для модулей первого класса (см. раздел 12.5) и обобщенных алгебраических типов данных (GADTs: см. раздел 12.10).

Полиморфный синтаксис

(Введен в OCaml 4.00)

let-binding ::= ...
∣ value-name : type { typeconstr-name }+ . typexpr = expr
class-field ::= ...
∣ method [private] method-name : type { typeconstr-name }+ . typexpr = expr
∣ method! [private] method-name : type { typeconstr-name }+ . typexpr = expr

Конструкция (type typeconstr-name) сама по себе не делает переменную типа, которую она вводит, полиморфной, но может быть объединена с явными полиморфными аннотациями при необходимости. Указанное выше правило представлено как синтаксический сахар для упрощения:

let rec f : type t1 t2. t1 * t2 list -> t1 = …

автоматически раскрывается в

let rec f : 't1 't2. 't1 * 't2 list -> 't1 =
  fun (type t1) (type t2) -> ( … : t1 * t2 list -> t1)

Этот синтаксис может быть очень полезен при определении рекурсивных функций, включающих GADTs, см. раздел 12.10 для более подробного объяснения.

Такая же функция предоставляется для определений методов.

© 1995-2022 INRIA.
https://v2.ocaml.org/releases/5.0/htmlman/locallyabstract.html

Spec-Zone.ru

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