Синтаксис записи на Haskell - PullRequest
48 голосов
/ 20 марта 2011

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

Вместо такого заявления:

data Foo = Foo { 
  fooID :: Int, 
  fooName :: String 
} deriving (Show)

Мне кажется, что-то в этом роде было бы более привлекательным:

data Foo = Foo id   :: Int
               name :: String
               deriving (Show)

Я уверен, что тамДолжно быть, это хорошая причина, по которой я скучаю, но почему С-подобный синтаксис записей был принят вместо более чистого подхода на основе компоновки?

Во-вторых, есть ли что-то в конвейере для решения проблемы пространства имен, поэтомуможете написать id foo вместо fooID foo в будущих версиях Haskell?(Помимо доступных в настоящее время обходных путей на основе классов типов longwinded.)

Ответы [ 3 ]

45 голосов
/ 02 апреля 2011

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

tl; dr

Вопрос 1: Именно так катились кости.Это был случайный выбор, и он застрял.

Вопрос 2: Да (Сорта).Несколько разных сторон наверняка задумывались над этой проблемой.

Продолжайте читать очень длинное объяснение каждого ответа, основанное на ссылках и цитатах, которые я считаю уместными и интересными.

Почему синтаксис C-подобных записей был принят вместо более чистого подхода, основанного на макете?

Исследователи Microsoft написали History of Haskell .Раздел 5.6 рассказывает о записях.Я процитирую первый небольшой кусочек, который проницателен:

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

Затем представители микрорайонов отвечают на свой собственный вопрос

Самой веской причиной, по-видимому, было отсутствиеочевидный «правильный» дизайн.

Вы можете прочитать статью самостоятельно для деталей, но они говорят, что Haskell в конечном итоге принял синтаксис записи из-за «давления для именованных полей в структурах данных».

К тому времени, когда разрабатывался проект Haskell 1.3, в 1993 году давление пользователей на именованные поля в структурах данных было сильным, поэтому в конечном итоге комитет принял минималистский дизайн ...

Вы спрашиваете, почему это так?Ну, насколько я понимаю, если бы ранние Хаскелеры имели свой путь, мы могли бы вообще не иметь синтаксиса записей.Эта идея, очевидно, была продвинута на Haskell людьми, которые уже привыкли к C-подобному синтаксису и были более заинтересованы в том, чтобы вводить C-подобные вещи в Haskell, а не делать что-то «способом Haskell». (Да, я понимаю, что это чрезвычайно субъективная интерпретация. Я мог бы ошибаться, но при отсутствии лучших ответов это лучший вывод, который я могу сделать.)

Есть ли что-нибудь в конвейере для решения проблемы пространства имен?

Прежде всего, не все считают, что это проблема.Несколько недель назад энтузиаст Racket объяснил мне (и другим), что иметь разные функции с одним и тем же именем было плохой идеей, потому что это усложняет анализ "что делает функция с именем ___?"На самом деле это не одна функция, а много.Идея может быть очень хлопотной для Haskell, поскольку она усложняет вывод типов.

Слегка касаясь вопроса, у Microsofties есть интересные вещи, которые можно сказать о классах типов Haskell:

Это было счастливымСовпадение сроков, что Уодлер и Блотт выдвинули эту ключевую идею, как раз в тот момент, когда языковой дизайн был еще в потоке.

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

В любом случае, есть несколько интересных способов решения этой «проблемы»:

Разрешение типа, направленное на имя Предлагаемая модификация Haskell (упоминается в комментариях выше).Просто прочитайте эту страницу, чтобы увидеть, что она затрагивает многие области языка.В целом, это не плохая идея.Много мыслей было вложено в это, чтобы оно не сталкивалось с вещами.Тем не менее, это все еще потребует значительно большего внимания, чтобы перевести его на теперь (более) зрелый язык Haskell.

Anotее статья Microsoft, OO Haskell , специально предлагает расширение языка Haskell для поддержки "специальной перегрузки".Это довольно сложно, так что вам просто нужно проверить Раздел 4 для себя.Суть его заключается в том, чтобы автоматически (?) Выводить типы «Имеет» и добавлять дополнительный шаг к проверке типов, которую они называют «улучшением», смутно обрисованную в приведенных ниже выборочных кавычках:

Учитывая ограничение класса Has_m (Int -> C -> r), существует только один экземпляр для m, который соответствует этому ограничению ... Поскольку существует только один выбор, мы должны сделать это сейчас, и это в свою очередь исправляет r, чтобы быть Int.Следовательно, мы получаем ожидаемый тип для f: f :: C -> Int -> IO Int ... [this] это просто выбор дизайна, основанный на идее, что класс Has_m закрыт

Извинения за некогерентное цитирование;если это вам вообще поможет, то отлично, иначе просто прочитайте статью.Это сложная (но убедительная) идея.

Крис Донец использовал Template Haskell, чтобы обеспечить типизацию утки в Haskell в некоторой степени аналогично бумаге OO Haskell (с использованием типов "Has"),Несколько интерактивных примеров сессий с его сайта:

λ> flap ^. donald
*Flap flap flap*
λ> flap ^. chris
I'm flapping my arms!

fly :: (Has Flap duck) => duck -> IO ()
fly duck = do go; go; go where go = flap ^. duck

λ> fly donald
*Flap flap flap*
*Flap flap flap*
*Flap flap flap*

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

8 голосов
/ 25 февраля 2014

Я просто подумал, что добавлю ссылку на проблему пространства имен.Кажется, что перегруженные поля записи для GHC поступают в GHC 7.10 (и, вероятно, уже находятся в HEAD), используя расширение OverloadedRecordFields .

Это позволитдля синтаксиса, такого как

data Person = Person { id :: Int, name :: String }
data Company { name :: String, employees :: [Person] }

companyNames :: Company -> [String]
companyNames c = name c : map name (employees c)
5 голосов
/ 20 марта 2011

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

Синтаксис записи

Несколько ударов в темноте: предлагаемый вами «основанный на макете» синтаксис очень похож на объявления без синтаксиса записи data объявления; что может привести к путанице при разборе (?)

--record
data Foo = Foo {i :: Int, s :: String} deriving (Show)
--non-record
data Foo = Foo Int String deriving (Show)
--new-record
data Foo = Foo i :: Int, s :: String deriving (Show)

--record
data LotsaInts = LI {a,b,c,i,j,k :: Int}
--new-record
data LostaInts = LI a,b,c,i,j,k :: Int

В последнем случае, к чему конкретно применяется :: Int? Вся декларация данных?

Объявления с синтаксисом записи (в настоящее время) аналогичны синтаксису построения и обновления. Синтаксис на основе макета не будет более понятным для этих случаев; как вы анализируете эти дополнительные = знаки?

let f1 = Foo {s = "foo1", i = 1}
let f2 = f1 {s = "foo2"}

let f1 = Foo s = "foo1", i = "foo2"
let f2 = f1 s = "foo2"

Откуда вы знаете f1 s является обновлением записи, в отличие от приложения-функции?

* 1026 Пространства имен *

Что если вы хотите смешать использование вашего класса id с прелюдией id? Как вы определяете, какой вы используете? Можете ли вы придумать какой-нибудь способ лучше, чем квалифицированный импорт и / или ключевое слово hiding?

import Prelude hiding (id)

data Foo = Foo {a,b,c,i,j,k :: Int, s :: String}
               deriving (Show)

id = i

ghci> :l data.hs
ghci> let foo = Foo 1 2 3 4 5 6 "foo"
ghci> id foo
4
ghci> Prelude.id f1
Foo {a = 1, b = 2, c = 3, i = 4, j = 5, k = 6, s = "foo"}

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

...