Варианты или полиморфные варианты? - PullRequest
34 голосов
/ 20 февраля 2012

Я заметил, что среди знакомых мне программистов на OCaml некоторые из них всегда используют полиморфные варианты (варианты, которые не объявлены, с префиксом с обратной кавычкой), в то время как другие никогда не используютполиморфные варианты и предпочтительные варианты, объявленные в типах.

За исключением соображений производительности (полиморфные варианты в настоящее время компилируются менее эффективно, чем простые варианты), как опытные разработчики OCaml могут выбирать между ними?

Ответы [ 3 ]

37 голосов
/ 21 февраля 2012

Мое использование можно разделить на следующие 5 категорий. 1. интерфейс 2. модульность 3. разборчивость 4. краткость 5. хитрости

  1. Если тип варианта является внутренним только для модуля, я использую обычные варианты, потому что, как вы сказали, они компилируются более эффективно.
  2. Если тип варианта экспортируется в интерфейсе, и я чувствую, что некоторые случаи могут появляться в других модулях, но не обязательно имеет смысл устанавливать их зависимость от модуля, я использую полиморфные варианты, потому что они не привязаны к система пространств имен модулей. Примеры: тип кодировки тип Xmlm. Кроме того, наличие типа сигнала в качестве типа варианта означает, что вы можете разрабатывать модули, используя ту же идею для обработки XML, не вводя зависимость от Xmlm.
  3. Если тип варианта экспортируется в интерфейсе, я считаю, что иногда слишком многословно использовать обычные варианты, когда значения типа варианта передаются функциям модуля. Пример: тип версии из Uuidm. Вместо того, чтобы писать Uuidm.create Uuidm.V4, вы можете просто написать Uuidm.create `V4, что так же ясно и менее многословно.
  4. Иногда определенная функция может возвращать разные случаи. Если эти случаи используются только этой функцией, я объявляю тип функции в интерфейсе, не вводя определение типа. Например parse : string -> [`Error of string | `Ok of t]
  5. Полиморфные варианты и их подтипы позволяют применять статические инварианты с фантомными типами. Кроме того, возможность их постепенного определения может быть полезна как для статического применения инвариантов, так и для целей документирования.

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

14 голосов
/ 20 февраля 2012

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

Если бы следующее могло работать, полиморфные варианты больше не были бы полезны в большинстве случаев:

type t1 = String of string | Int of int | Bool of bool | List of t1 list
type t2 = String of string | Int of int | Other

let simplify x =
  match (x : t1) with
      String s -> String s
    | Int n -> Int n
    | Bool _
    | List _ -> Other

2014-02-21 Обновление: приведенный выше код теперь действителен в OCaml 4.01.Ура!

12 голосов
/ 26 февраля 2012

Это неправда, что полиморфные варианты всегда менее эффективны.Используя пример Мартина:

type base = [`String of string | `Int of int]
type t1 = [base | `Bool of bool | `List of t1 list]
type t2 = [base | `Other]

let simplify (x:t1):t2 = match x with
| #base as b -> b
| `Bool _ | `List _ -> `Other

Чтобы сделать это со стандартными вариантами, требуется два различных типа и полное перекодирование, при полиморфных вариантах базовый случай является физически инвариантным.Эта функция действительно вступает в свои права при использовании открытой рекурсии для переписывания терминов:

type leaf = [`String of string | `Int of int]
type 'b base = [leaf | `List of 'b list]
type t1 = [t1 base | `Bool of bool ]
type t2 = [t2 base | `Other]

let rec simplify (x:t1):t2 = match x with
| #leaf as x -> x
| `List t -> `List (List.map simplify t)
| `Bool _ -> `Other

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

К сожалению, Хиндли из Окамла- Вывод типа Миллера недостаточно силен, чтобы делать подобные вещи без явной типизации, что требует тщательной факторизации типов, что, в свою очередь, затрудняет прототипирование.Кроме того, иногда требуются явные приведения.

Большим недостатком этого метода является то, что для терминов с несколькими параметрами вскоре возникает довольно запутанный комбинаторный взрыв типов, и в конце концов его легче датьнад статическим применением и используйте тип кухонной раковины с подстановочными знаками и исключениями (например, динамическая типизация).

...