Arhn - архитектура программирования

Когда следует использовать расширяемые вариантные типы в OCaml?

Я прошел курс по OCaml перед расширяемыми типами вариантов были представлены, и я мало о них знаю. У меня несколько вопросов:

  1. (Этот вопрос был удален, поскольку за него проголосовали "объективно не отвечающие".)
  2. Каковы низкоуровневые последствия использования EVT, такие как производительность, представление памяти и (от) маршалинг?

Обратите внимание, что мой вопрос касается конкретно типа расширяемого варианта, в отличие от вопроса, предложенного как идентичного этому (этот вопрос был задан до введения EVT!).

17.02.2019

  • Возможный дубликат вариантов или полиморфных вариантов? 17.02.2019
  • Вы можете привести пример того, о чем говорите? Связано ли это с этим запросом на вытягивание? Раньше полиморфные варианты также назывались открытыми вариантами, потому что они открыты для расширения, поэтому нетрудно предположить, что их можно было бы назвать расширяемыми вариантами. Если вы говорите о новой функции, добавление примера кода поможет для ясности. (Я пометил как возможный дубликат, но снял флажок.) 17.02.2019

Ответы:


1

Расширяемые варианты сильно отличаются от стандартных вариантов с точки зрения поведения во время выполнения.

В частности, конструкторы расширений - это значения времени выполнения, которые находятся внутри модуля, в котором они были определены. Например, в

 type t = ..
 module M = struct
   type t +=A
 end
 open M

вторая строка определяет новое значение конструктора расширения A и добавляет его к существующим конструкторам расширения M во время выполнения. Напротив, классических вариантов во время выполнения на самом деле не существует.

Можно заметить эту разницу, заметив, что я могу использовать модуль компиляции только для mli для классических вариантов:

 (* classical.mli *)
 type t = A

 (* main.ml *)
 let x = Classical.A

а затем скомпилировать main.ml с

ocamlopt classic.mli main.ml

без проблем, потому что в модуле Classical нет значения.

В отличие от расширяемых вариантов это невозможно. Если у меня есть

 (* ext.mli *)
  type t = ..
  type t+=A

 (* main.ml *)
 let x = Ext.A

тогда команда

ocamlopt ext.mli main.ml

терпит неудачу с

Ошибка: требуемый модуль `Ext 'недоступен

потому что значение времени выполнения для конструктора расширения Ext.A отсутствует.

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

 let a = [%extension_constructor A]
 Obj.extension_name a;;
  • : string = "M.A"
 Obj.extension_id a;;
  • : int = 144

(Этот id довольно хрупкий, и его значение не имеет особого смысла.) Важным моментом является то, что конструкторы расширений различаются по их местоположению в памяти. Следовательно, конструкторы с n аргументами реализуются как блок с n+1 аргументами, где первым скрытым аргументом является конструктор расширения:

type t += B of int
let x = B 0;;

Здесь x содержит два поля, а не одно:

 Obj.size (Obj.repr x);;
  • : int = 2

И первое поле - это конструктор расширения B:

 Obj.field (Obj.repr x) 0 == Obj.repr [%extension_constructor B];;
  • : bool = true

Предыдущий оператор также работает для n=0: расширяемые варианты никогда не представляются как целые числа с тегами, в отличие от классических вариантов.

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

 let round_trip (x:'a):'a = Marshall.from_string (Marshall.to_string x []) 0

затем проверьте результат с помощью

  type t += C
  let is_c = function
  | C -> true
  | _ -> false

приводит к отказу:

   is_c (round_trip C)
  • : bool = false

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

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

 type s = A of int | B of int

и определим функцию f как

let f = function
| A n | B n -> n

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

Вы можете проверить с помощью ocamlc -dlambda, что указанная выше функция представлена ​​в промежуточном представлении Lambda как:

(function param/1008 (field 0 param/1008)))

Однако с расширяемыми вариантами не только нам нужен шаблон по умолчанию.

   type e = ..
   type e += A of n | B of n
   let g = function
   | A n | B n -> n
   | _ -> 0

но нам также нужно сравнить аргумент с каждым конструктором расширения в сопоставлении, что приведет к более сложному лямбда-IR для сопоставления

 (function param/1009
   (catch
     (if (== (field 0 param/1009) A/1003) (exit 1 (field 1 param/1009))
       (if (== (field 0 param/1009) B/1004) (exit 1 (field 1 param/1009))
         0))
    with (1 n/1007) n/1007)))

Наконец, чтобы завершить реальный пример расширяемых вариантов, в OCaml 4.08 модуль Format заменил свои строковые пользовательские теги расширяемыми вариантами.

Это означает, что определение новых тегов выглядит так:

Во-первых, мы начнем с фактического определения новых тегов.

 type t =  Format.stag = ..
 type Format.stag += Warning | Error

Затем функции перевода для этих новых тегов

let mark_open_stag tag =
match tag with
| Error -> "\x1b[31m" (* aka print the content of the tag in red *)
| Warning -> "\x1b[35m" (* ... in purple *)
| _ -> ""

let mark_close_stag _tag =
  "\x1b[0m" (*reset *)

Затем установка нового тега выполняется с помощью

 let enable ppf =
    Format.pp_set_tags ppf true;
    Format.pp_set_mark_tags ppf true;
    Format.pp_set_formatter_stag_functions ppf
    { (Format.pp_get_formatter_stag_functions ppf ()) with
    mark_open_stag; mark_close_stag }

С помощью некоторой вспомогательной функции печать с этими новыми тегами может выполняться с помощью

 Format.printf "This message is %a.@." error "important"
 Format.printf "This one %a.@." warning "not so much"

По сравнению со строковыми тегами есть несколько преимуществ:

  • меньше места для орфографической ошибки
  • нет необходимости сериализовать / десериализовать потенциально сложные данные
  • не перепутайте разные конструкторы расширений с тем же именем.
  • Таким образом, объединение нескольких определяемых пользователем функций mark_open_stag безопасно: каждая функция может распознавать только свои собственные конструкторы расширения.
25.02.2019
  • Можете ли вы уточнить, что представляет собой представление памяти для случая расширяемого варианта с нулевым значением (тип t + = Foo)? 20.12.2019
  • Для конструкторов с нулевым значением используется непосредственно конструктор внутреннего расширения, то есть Obj.repr Foo == [%extension_constructor Foo]. 21.12.2019
  • Новые материалы

    Коллекции публикаций по глубокому обучению
    Последние пару месяцев я создавал коллекции последних академических публикаций по различным подполям глубокого обучения в моем блоге https://amundtveit.com - эта публикация дает обзор 25..

    Представляем: Pepita
    Фреймворк JavaScript с открытым исходным кодом Я знаю, что недостатка в фреймворках JavaScript нет. Но я просто не мог остановиться. Я хотел написать что-то сам, со своими собственными..

    Советы по коду Laravel #2
    1-) Найти // You can specify the columns you need // in when you use the find method on a model User::find(‘id’, [‘email’,’name’]); // You can increment or decrement // a field in..

    Работа с временными рядами спутниковых изображений, часть 3 (аналитика данных)
    Анализ временных рядов спутниковых изображений для данных наблюдений за большой Землей (arXiv) Автор: Рольф Симоэс , Жильберто Камара , Жильберто Кейрос , Фелипе Соуза , Педро Р. Андраде ,..

    3 способа решить квадратное уравнение (3-й мой любимый) -
    1. Методом факторизации — 2. Используя квадратичную формулу — 3. Заполнив квадрат — Давайте поймем это, решив это простое уравнение: Мы пытаемся сделать LHS,..

    Создание VR-миров с A-Frame
    Виртуальная реальность (и дополненная реальность) стали главными модными терминами в образовательных технологиях. С недорогими VR-гарнитурами, такими как Google Cardboard , и использованием..

    Демистификация рекурсии
    КОДЕКС Демистификация рекурсии Упрощенная концепция ошеломляющей О чем весь этот шум? Рекурсия, кажется, единственная тема, от которой у каждого начинающего студента-информатика..