Почему на Хаскеле нет символов (а-ля рубин) / атомов (а-ля эрланг)? - PullRequest
15 голосов
/ 29 мая 2011

Два языка, в которых я использовал символы - это Ruby и Erlang, и я всегда считал их чрезвычайно полезными.

У Haskell есть алгебраические типы данных, но я все еще думаю, что символы были бы очень удобными. Непосредственное использование, которое приходит на ум, состоит в том, что, поскольку символы изоморфны целым числам, вы можете использовать их там, где вы использовали бы интеграл или строку «первичный ключ».

Синтаксический сахар для атомов может быть второстепенным - что-то или является атомом. Все атомы являются экземплярами типа с именем Atom, который выводит Show и Eq. Затем вы можете использовать его для более наглядных кодов ошибок, например

type ErrorCode = Atom
type Message = String
data Error = Error ErrorCode Message
loginError = Error :redirect "Please login first"

В этом случае: перенаправление более эффективно, чем использование строки («перенаправление»), и его легче понять, чем целое число (404).

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

Так почему же символы не были добавлены в язык? Или я думаю об этом не так?

Ответы [ 5 ]

17 голосов
/ 30 мая 2011

Я согласен с ответом camccann, что он, вероятно, отсутствует в основном потому, что его нужно было бы внедрить довольно глубоко в реализацию, и он слишком мал для использования на этом уровне сложности.В Erlang (и Prolog и Lisp) символы (или атомы) обычно служат специальными маркерами и служат в основном тем же понятием, что и конструктор.В Лисп динамическая среда включает в себя компилятор, поэтому это также (полезная) концепция компилятора, просочившаяся во время выполнения.

Проблема в следующем, интернирование символов нечисто (оно модифицирует таблицу символов).Поскольку мы никогда не модифицируем существующий объект, он, однако, прозрачен по ссылкам, но если реализован наивно, может привести к утечкам пространства во время выполнения.На самом деле, как в настоящее время реализовано в Erlang, вы можете фактически вывести из строя виртуальную машину, перепутав слишком много символов / атомов (я думаю, что текущий предел составляет 2 ^ 20), потому что они никогда не могут собрать мусор.Это также трудно реализовать в параллельной установке без огромной блокировки вокруг таблицы символов.

Однако обе проблемы могут быть (и были) решены.Например, см. Erlang EEP 20 .Я использую эту технику в пакете simple-atom .Он использует unsafePerformIO под капотом, но только (надеюсь) в редких случаях.Он все еще может использовать некоторую помощь от GC для выполнения оптимизации, аналогичной сокращению косвенного обращения.Он также использует довольно много IORef с внутренней стороны, что не слишком хорошо для производительности и использования памяти.

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

14 голосов
/ 29 мая 2011

Я думаю, что самый простой ответ заключается в том, что из того, что используются в символах в стиле Лисп (я думаю, что и Руби, и Эрланг получили идею), в Хаскеле большинство из них:

  • Уже сделано каким-либо другим способом - например, тип данных с кучей нулевых конструкторов, которые также ведут себя как «удобные имена для целых чисел».

  • Неудобно, чтобы соответствоватьв - вещи, которые существуют на уровне синтаксиса языка, а не являются обычными данными, обычно имеют больше информации о типе, связанной с ними, но символы должны были бы быть отличными друг от друга типами (почти бесполезными без некоторой упрощенной специальной суммы)type) или все того же типа (в этом случае они почти не отличаются от использования строк).

Кроме того, имейте в виду, что сам Haskell на самом деле очень и очень маленький язык,Очень мало «запекается», и большинство вещей - это просто синтаксический сахар для других примитивов.Это немного менее верно, если вы включаете несколько расширений GHC, но GHC с -XAndTheKitchenSinkToo не является тем же языком, что и собственно Haskell.

Кроме того, Haskell очень поддается псевдосинтаксису и метапрограммированию, так что естьмногое можно сделать даже без встроенного. Особенно, если вы попадаете в мета-программирование TH и страшного типа и все остальное.

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

9 голосов
/ 29 мая 2011

Атомы не предоставляются языком, но могут быть разумно реализованы в виде библиотеки:

http://hackage.haskell.org/package/simple-atom

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

3 голосов
/ 29 мая 2011

Haskell использует конструкторы типов * вместо символов, так что набор символов, которые может принимать функция, закрыт, и может быть рассмотрен системой типов.Вы можете добавить символы к языку, но это поместит вас в то же место, что и строки: вам нужно будет сравнить все возможные символы с теми, которые имеют известные значения во время выполнения, добавить обработку ошибок повсюду и т. Д.Это будет большой обходной путь для всей проверки во время компиляции.

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

  • Я больше знаком с OCaml, чем с Haskell, так чтоконструктор "не может быть правильным термином.Такие вещи, как None или Just 3.
1 голос
/ 29 мая 2011

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

Вместо этого используйте Enum.

data FileType = GZipped | BZipped | Plain
  deriving Enum

descr ft  =  ["compressed with gzip",
              "compressed with bzip2",
              "uncompressed"] !! fromEnum ft
...