Что такого плохого в шаблоне Haskell?

252

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

Я видел различные посты в блогах, где люди делают довольно аккуратные вещи с Template Haskell, позволяя использовать более симпатичный синтаксис, который просто невозможен в обычном Haskell, а также огромное сокращение шаблонов. Так почему же на шаблон Хаскелла смотрят свысока? Что делает это нежелательным? При каких обстоятельствах следует избегать Template Haskell и почему?

Дэн Бертон
источник
56
Я не согласен с голосованием переехать; Я задаю этот вопрос в том же духе, что и я. Что такого плохого в Lazy I / O? и я ожидаю увидеть ответы таким же образом. Я открыт для переписывания вопроса, поможет ли это.
Дэн Бертон
51
@ErikPhilips Почему вы не позволяете людям, которые часто посещают этот тег, решать, принадлежит ли он здесь? Похоже, что ваше единственное взаимодействие с сообществом Haskell - это задать свои вопросы.
Габриэль Гонсалес
5
@GabrielGonzalez очевидно с текущим вопросом и ответом, что он не следует за FAQ под каким вопросом я не должен здесь задавать: нет никакой реальной проблемы, которая должна быть решена . Вопрос не решает специфическую для кода проблему и носит только концептуальный характер. И если исходить из вопроса, следует ли избегать использования шаблона haskell, он также попадает в переполнение стека и не является механизмом рекомендаций .
Эрик Филипс
27
@ErikPhilips Аспект механизма рекомендаций не имеет отношения к этому вопросу, потому что вы заметите, что это относится к решению между различными инструментами (например, «скажите мне, какой язык мне следует использовать»). Напротив, я просто прошу объяснений, касающихся конкретно шаблона Haskell, и в FAQ говорится: «Если вы мотивируете себя тем, что« я бы хотел, чтобы другие объяснили [пусто] мне », то вы, вероятно, в порядке». Сравнивать, например, с GOTO по-прежнему считается вредным?
Дэн Бертон
29
Голосование возобновить. Тот факт, что это вопрос более высокого уровня, не означает, что он не очень хороший.
György Andrasek

Ответы:

171

Одна из причин, по которой следует избегать Template Haskell, заключается в том, что он вообще не является типобезопасным, что противоречит большей части «духа Haskell». Вот несколько примеров этого:

  • Вы не можете контролировать, какой тип Haskell AST будет генерировать часть кода TH, за пределами того, где он появится; у вас может быть значение типа Exp, но вы не знаете, является ли это выражением, представляющим a [Char]или a (a -> (forall b . b -> c))или что-то еще. TH был бы более надежным, если бы можно было выразить, что функция может генерировать только выражения определенного типа, или только объявления функций, или только шаблоны соответствия конструкторам данных и т. Д.
  • Вы можете генерировать выражения, которые не компилируются. Вы сгенерировали выражение, которое ссылается на свободную переменную foo, которая не существует? Не повезло, вы увидите это только при использовании генератора кода и только при обстоятельствах, которые инициируют генерацию этого конкретного кода. Модульное тестирование тоже очень сложно.

ТХ тоже откровенно опасен

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

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

  • Код TH не всегда может быть компонован. Допустим, кто-то делает генератор для линз, и чаще всего этот генератор будет структурирован таким образом, что его может вызывать только «конечный пользователь», а не другой код TH, например, принимая список конструкторов типов для генерации линз в качестве параметра. Сложно сгенерировать этот список в коде, а пользователю остается только написать generateLenses [''Foo, ''Bar].
  • Разработчики даже не знают, что код TH может быть составлен. Знаете ли вы, что вы можете написать forM_ [''Foo, ''Bar] generateLens? Qэто просто монада, так что вы можете использовать все обычные функции на нем. Некоторые люди не знают этого, и из-за этого они создают несколько перегруженных версий по существу одних и тех же функций с одинаковыми функциями, и эти функции приводят к определенному эффекту раздувания. Кроме того, большинство людей пишут свои генераторы в Qмонаде, даже когда им это не нужно, что походит на написание bla :: IO Int; bla = return 3; вы предоставляете функции больше «среды», чем нужно, и клиенты этой функции обязаны предоставлять эту среду в качестве эффекта этого.

Наконец, есть некоторые вещи, которые делают функции TH менее увлекательными для использования в качестве конечного пользователя:

  • Непрозрачность. Когда функция TH имеет тип Q Dec, она может генерировать абсолютно все на верхнем уровне модуля, и вы не имеете абсолютно никакого контроля над тем, что будет сгенерировано.
  • Монолитность. Вы не можете контролировать, сколько генерирует функция TH, если разработчик не позволяет это; если вы найдете функцию, которая генерирует интерфейс базы данных и интерфейс сериализации JSON, вы не сможете сказать: «Нет, мне нужен только интерфейс базы данных, спасибо; я буду катать свой собственный интерфейс JSON»
  • Время выполнения. Код TH занимает относительно много времени для запуска. Код интерпретируется заново каждый раз, когда файл компилируется, и часто для запуска загружаемого кода TH требуется тонна пакетов, которые необходимо загрузить. Это значительно замедляет время компиляции.
dflemstr
источник
4
Добавьте к этому тот факт, что template-haskell исторически очень плохо документирован. (Хотя я только что посмотрел еще раз, и кажется, что сейчас, по крайней мере, немного лучше.) Кроме того, чтобы понять template-haskell, вам, по сути, нужно понимать грамматику языка Haskell, которая налагает определенную сложность (это не схема). Эти две вещи помогли мне преднамеренно не потрудиться понять TH, когда я был новичком в Haskell.
mightybyte
14
Не забывайте, что использование шаблона Haskell неожиданно означает, что порядок объявлений имеет значение! TH просто не так тесно интегрирован, как можно было бы надеяться, учитывая гладкую полировку Haskell (будь то 1.4, '98, 2010 или даже Глазго).
Томас М. Дюбюссон
13
Вы можете рассуждать о Haskell без особых затруднений, такой гарантии у Template Haskell нет.
августа
15
А что случилось с обещанием Олега о безопасной для типов альтернативе TH? Я имею в виду его работы основаны от его «Наконец Tagless, частично Оценивается» бумага и больше его нот здесь . Это выглядело так многообещающе, когда они объявили об этом, и тогда я никогда не слышал об этом ни слова.
Габриэль Гонсалес
53

Это исключительно мое собственное мнение.

  • Это некрасиво использовать. $(fooBar ''Asdf)просто не выглядит красиво. Поверхностно, конечно, но это способствует.

  • Еще страшнее писать. Цитирование иногда срабатывает, но большую часть времени вам приходится делать прививку AST вручную и сантехнику. API является большим и громоздким, всегда есть много случаев , вы не заботитесь о том, но все же нужно отправки, и случаи , которые вы делаете заботу о , как правило, присутствует в нескольких сходных , но не идентичных форм (данные против Newtype, запись стиль против нормальных конструкторов и т. д.). Писать скучно и многократно, достаточно сложно, чтобы не быть механическим. Предложение по реформе решает некоторые из этих вопросов (делая цитаты более применимыми).

  • Сценическое ограничение - ад. Неспособность объединить функции, определенные в одном и том же модуле, является меньшей его частью: другое следствие - если у вас есть объединение верхнего уровня, все, что находится после него в модуле, будет вне области действия чего-либо до него. Другие языки с этим свойством (C, C ++) делают его работоспособным, позволяя вам перенаправлять объявления, но Haskell этого не делает. Если вам нужны циклические ссылки между объединенными объявлениями или их зависимостями и зависимостями, вы обычно просто испорчены.

  • Это недисциплинировано. Под этим я подразумеваю, что в большинстве случаев, когда вы выражаете абстракцию, за этой абстракцией стоит какой-то принцип или концепция. Для многих абстракций принцип, лежащий в их основе, может быть выражен в их типах. Для классов типов вы можете часто формулировать законы, которым должны подчиняться экземпляры и которые могут принимать клиенты. Если вы используете новую универсальную функцию GHC для абстрагирования формы объявления экземпляра для любого типа данных (в пределах границ), вы можете сказать: «для типов суммы это работает так, для типов продукта - так». Шаблон Haskell, с другой стороны, является просто макросом. Это не абстракция на уровне идей, а абстракция на уровне AST, что лучше, но скромно, чем абстракция на уровне простого текста. *

  • Это связывает вас с GHC. Теоретически другой компилятор мог бы реализовать это, но на практике я сомневаюсь, что это когда-нибудь случится. (Это в отличие от различных расширений системы типов, которые, хотя они могут быть реализованы только GHC на данный момент, я легко мог представить себе, что они будут приняты другими компиляторами в будущем и в конечном итоге стандартизированы.)

  • API не стабилен. Когда в GHC добавляются новые языковые функции, а пакет template-haskell обновляется для их поддержки, это часто связано с несовместимыми с обратным характером изменениями типов данных TH. Если вы хотите, чтобы ваш код TH был совместим с более чем одной версией GHC, вам нужно быть очень осторожным и, возможно, использовать его CPP.

  • Существует общий принцип, что вы должны использовать правильный инструмент для работы и самый маленький, который будет достаточным, и в этой аналогии шаблон Haskell выглядит примерно так . Если есть способ сделать это, а не Template Haskell, это, как правило, предпочтительнее.

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

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

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

РЕДАКТИРОВАТЬ 23-04-14: То, что я часто пытался получить в вышеизложенном, и только недавно понял точно, что есть важное различие между абстракцией и дедупликацией. Правильная абстракция часто приводит к дедупликации как побочному эффекту, а дублирование часто является явным признаком неадекватной абстракции, но это не то, почему это ценно. Правильная абстракция - это то, что делает код правильным, понятным и обслуживаемым. Дедупликация только делает ее короче. Шаблон Haskell, как и макросы в целом, является инструментом для дедупликации.

glaebhoerl
источник
«CPP имеет лучшее отношение мощности к весу для тех проблем, которые он может решить». На самом деле. И в C99 он может решить все, что вы хотите. Рассмотрим это: COS , Chaos . Я также не понимаю, почему люди думают, что поколение AST лучше. Это просто более двусмысленно и менее ортогонально к другим языковым особенностям
Бриттон Керин
31

Я хотел бы остановиться на нескольких моментах, которые поднимает dflemstr.

Я не нахожу тот факт, что вы не можете перепроверять TH, чтобы это беспокоило. Зачем? Потому что даже если есть ошибка, это все равно будет время компиляции. Я не уверен, усиливает ли это мои аргументы, но по духу это похоже на ошибки, которые вы получаете при использовании шаблонов в C ++. Я думаю, что эти ошибки более понятны, чем ошибки C ++, поскольку вы получите довольно напечатанную версию сгенерированного кода.

Если выражение TH / квазиквотер делает что-то настолько продвинутое, что хитрые углы могут скрыться, то, возможно, это опрометчиво?

Я немного нарушаю это правило с помощью квазиквотеров, над которыми я работал в последнее время (используя haskell-src-exts / meta) - https://github.com/mgsloan/quasi-extras/tree/master/examples . Я знаю, что это приводит к некоторым ошибкам, таким как неспособность объединить обобщенные списки. Тем не менее, я думаю, что есть хороший шанс, что некоторые идеи из http://hackage.haskell.org/trac/ghc/blog/Template%20Haskell%20Proposal окажутся в компиляторе. До тех пор библиотеки для разбора Haskell на TH-деревья являются почти идеальным приближением.

Что касается скорости / зависимостей компиляции, мы можем использовать «нулевой» пакет для вставки сгенерированного кода. Это, по крайней мере, хорошо для пользователей данной библиотеки, но мы не можем добиться большего успеха в случае редактирования библиотеки. Могут ли зависимости TH раздуть сгенерированные двоичные файлы? Я думал, что это исключило все, на что не ссылается скомпилированный код.

Ограничение этапов / разбиение этапов компиляции модуля Haskell отстой.

RE Непрозрачность: это то же самое для любой библиотечной функции, которую вы вызываете. Вы не можете контролировать, что будет делать Data.List.groupBy. У вас просто есть разумная «гарантия» / соглашение о том, что номера версий говорят вам о совместимости. Это несколько другой вопрос изменений, когда.

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

RE Монолитизм: Вы можете, конечно, постобработать результаты выражения TH, используя свой собственный код времени компиляции. Было бы не так уж много кода для фильтрации по типу / имени объявления верхнего уровня. Черт возьми, вы можете себе представить написание функции, которая делает это в общем. Для модификации / демонолитизации квазиквотеров вы можете сопоставить шаблон с «QuasiQuoter» и извлечь использованные преобразования или сделать новые с точки зрения старых.

mgsloan
источник
1
Относительно непрозрачности / монолитизма: Вы, конечно, можете пройтись [Dec]и удалить ненужные элементы, но допустим, что функция читает внешний файл определения при генерации интерфейса JSON. Тот факт, что вы не используете его, Decне останавливает генератор при поиске файла определения, что приводит к сбою компиляции. По этой причине было бы неплохо иметь более ограниченную версию Qмонады, которая позволяла бы вам генерировать новые имена (и тому подобное), но не позволяла бы IO, чтобы, как вы говорите, можно было фильтровать его результаты / делать другие композиции ,
dflemstr
1
Я согласен, должна быть не-IO версия Q / цитата! Это также поможет решить - stackoverflow.com/questions/7107308/… . Как только вы убедитесь, что код во время компиляции не делает ничего небезопасного, создается впечатление, что вы можете просто запустить проверку безопасности для полученного кода и убедиться, что он не ссылается на личные вещи.
Mgsloan
1
Ты когда-нибудь писал свой контраргумент? Все еще жду вашей обещанной ссылки. Для тех, кто ищет старое содержание этого ответа: stackoverflow.com/revisions/10859441/1 , и для тех, кто может просматривать удаленный контент: stackoverflow.com/revisions/10913718/6
Дэн Бертон,
1
есть ли более новая версия нулевой версии, чем та, что взломана? Последний (и репозиторий darcs) последний раз обновлялся в 2009 году. Обе копии не создаются с текущим ghc (7.6).
aavogt
1
@aavogt tgeeky работала над его исправлением, но я не думаю, что он закончил: github.com/technogeeky/zeroth Если никто не сделает это / сделает что-то для этого, я в конце концов доберусь до этого.
Mgsloan
16

Этот ответ является ответом на вопросы, поднятые Иллисусом, пункт за пунктом:

  • Это некрасиво использовать. $ (fooBar '' Asdf) просто не выглядит красиво. Поверхностно, конечно, но это способствует.

Я согласен. Я чувствую, что $ () был выбран, чтобы выглядеть так, как будто он был частью языка - используя знакомую символьную палитру Хаскелла. Тем не менее, это именно то, что вы / не хотите / хотите в символах, используемых для сплайсинга макросов. Они определенно смешиваются слишком много, и этот косметический аспект очень важен. Мне нравится внешний вид {{}} для сростков, потому что они довольно визуально различимы.

  • Еще страшнее писать. Цитирование иногда срабатывает, но большую часть времени вам приходится делать прививку AST вручную и сантехнику. [API] [1] является большим и громоздким, всегда есть много случаев, о которых вы не заботитесь, но по-прежнему нуждаетесь в отправке, и случаи, о которых вы заботитесь, обычно присутствуют в нескольких похожих, но не идентичных формах (данные против нового типа, стиля записи против обычных конструкторов и т. д.). Писать скучно и многократно, достаточно сложно, чтобы не быть механическим. [Предложение о реформе] [2] решает некоторые из этих вопросов (делая цитаты более применимыми).

Я также согласен с этим, однако, как отмечают некоторые из комментариев в «Новых направлениях для TH», отсутствие хороших готовых цитат из AST не является критическим недостатком. В этом пакете WIP я пытаюсь решить эти проблемы в виде библиотеки: https://github.com/mgsloan/quasi-extras . До сих пор я допускаю сращивание в нескольких местах, чем обычно, и могу сопоставлять шаблоны на AST.

  • Сценическое ограничение - ад. Неспособность объединить функции, определенные в одном и том же модуле, является меньшей его частью: другое следствие - если у вас есть объединение верхнего уровня, все, что находится после него в модуле, будет вне области действия чего-либо до него. Другие языки с этим свойством (C, C ++) делают его работоспособным, позволяя вам перенаправлять объявления, но Haskell этого не делает. Если вам нужны циклические ссылки между объединенными объявлениями или их зависимостями и зависимостями, вы обычно просто испорчены.

Я столкнулся с проблемой невозможности определения циклического TH раньше ... Это довольно раздражает. Есть решение, но оно уродливо - оберните вещи, связанные с циклической зависимостью, в выражение TH, которое объединяет все сгенерированные объявления. Одним из таких генераторов объявлений может быть просто квазиквотер, который принимает код на Haskell.

  • Это беспринципно. Под этим я подразумеваю, что в большинстве случаев, когда вы выражаете абстракцию, за этой абстракцией стоит какой-то принцип или концепция. Для многих абстракций принцип, лежащий в их основе, может быть выражен в их типах. Когда вы определяете класс типов, вы часто можете сформулировать законы, которым должны подчиняться экземпляры и которые могут принимать клиенты. Если вы используете [новую универсальную функцию] GHC [3], чтобы абстрагировать форму объявления экземпляра над любым типом данных (в пределах границ), вы скажете: «для типов суммы это работает так, для типов продукта - так ». Но Template Haskell - это просто тупые макросы. Это не абстракция на уровне идей, а абстракция на уровне AST, что лучше, но скромно, чем абстракция на уровне простого текста.

Это только беспринципно, если вы делаете с ним беспринципные вещи. Единственное отличие состоит в том, что с компилятором реализованы механизмы для абстракции, у вас больше уверенности в том, что абстракция не протекает. Возможно, демократизация языкового дизайна звучит немного страшно! Создатели библиотек TH должны хорошо документировать и четко определять значение и результаты инструментов, которые они предоставляют. Хорошим примером принципиального TH является производный пакет: http://hackage.haskell.org/package/derive - он использует DSL, так что пример многих дериваций / указывает / фактический деривация.

  • Это связывает вас с GHC. Теоретически другой компилятор мог бы реализовать это, но на практике я сомневаюсь, что это когда-нибудь случится. (Это в отличие от различных расширений системы типов, которые, хотя они могут быть реализованы только GHC на данный момент, я легко мог представить себе, что они будут приняты другими компиляторами в будущем и в конечном итоге стандартизированы.)

Это очень хороший момент - TH API довольно большой и неуклюжий. Реализация кажется, что это может быть сложно. Однако есть только несколько способов решить проблему представления AST на Haskell. Я полагаю, что копирование TH ADTs и написание конвертера во внутреннее представление AST поможет вам в этом. Это было бы эквивалентно (что немаловажно) усилиям по созданию haskell-src-meta. Это также можно было бы просто повторно реализовать, просто распечатав TH AST и используя внутренний синтаксический анализатор компилятора.

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

  • API не стабилен. Когда в GHC добавляются новые языковые функции, а пакет template-haskell обновляется для их поддержки, это часто связано с несовместимыми с обратным характером изменениями типов данных TH. Если вы хотите, чтобы ваш код TH был совместим с более чем одной версией GHC, вам нужно быть очень осторожным и, возможно, использовать его CPP.

Это тоже хороший момент, но несколько драматичный. Хотя в последнее время были добавлены API, они не вызывали частых поломок. Кроме того, я думаю, что благодаря вышеприведенному цитированию AST, о котором я упоминал ранее, API, который фактически должен использоваться, может быть существенно сокращен. Если никакое конструирование / сопоставление не требует отдельных функций и вместо этого выражается в виде литералов, то большая часть API исчезает. Более того, код, который вы пишете, будет проще переносить в представления AST для языков, похожих на Haskell.


Подводя итог, я думаю, что TH - это мощный инструмент, которым почти не уделяется должного внимания. Меньшее количество ненависти может привести к созданию более оживленной экосистемы библиотек, способствующей внедрению большего количества прототипов языковых функций. Было замечено, что TH - это мощный инструмент, который может позволить вам / делать / почти все. Анархия! Что ж, по моему мнению, эта мощь может позволить вам преодолеть большинство ее ограничений и создавать системы, способные к совершенно принципиальным подходам метапрограммирования. Стоит использовать уродливые хаки для имитации «правильной» реализации, поскольку таким образом дизайн «правильной» реализации постепенно станет понятен.

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

Каков типичный ответ Хаскелла на стандартный код? Абстракция. Какие наши любимые абстракции? Функции и классы типов!

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

  • Наборы минимальных привязок не объявляются / проверяется компилятором. Это может привести к непреднамеренным определениям, дающим основание из-за взаимной рекурсии.

  • Несмотря на большое удобство и мощь, которые это дает, вы не можете указать значения по умолчанию для суперкласса, поскольку экземпляры-сироты http://lukepalmer.wordpress.com/2009/01/25/a-world-without-orphans/ Это позволит нам исправить числовая иерархия изящно!

  • Следование TH-подобным возможностям по умолчанию для методов привело к http://www.haskell.org/haskellwiki/GHC.Generics . Хотя это классная штука, мой единственный опыт отладки кода с использованием этих обобщений был почти невозможен из-за размера типа индуцированного для и ADT, такого сложного, как AST. https://github.com/mgsloan/th-extra/commit/d7784d95d396eb3abdb409a24360beb03731c88c

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

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

Я думаю, что отказ от TH и метапрограммирование, подобное lisp, привело к предпочтению таких вещей, как метод-значения по умолчанию, а не к более гибкому, макро-расширению, как объявления экземпляров. Дисциплина избегания вещей, которые могут привести к непредвиденным результатам, является мудрой, однако, мы не должны игнорировать то, что способная система типов Хаскелла допускает более надежное метапрограммирование, чем во многих других средах (путем проверки сгенерированного кода).

mgsloan
источник
4
Этот ответ сам по себе не очень хорош: вы делаете несколько ссылок на другой ответ, который мне нужно найти и найти, прежде чем я смогу правильно прочитать ваш.
Бен Милвуд
Это так. Я пытался прояснить, о чем идет речь, несмотря на. Возможно я отредактирую, чтобы встроить пункты illisuis.
Mgsloan
Я должен сказать, что, возможно, «беспринципный» - более сильное слово, чем я должен был использовать, с некоторыми коннотациями, которые я не намеревался - это, конечно, не бессовестно! С этим пулевым пунктом у меня были самые большие проблемы, потому что у меня в голове было это чувство или не сформированная идея, и я не мог выразить это словами, а слово «беспринципный» было одним из слов, которые я уловил, и находился где-то поблизости. «Дисциплинированный», вероятно, ближе. Не имея четкой и лаконичной формулировки, я использовал несколько примеров. Если бы кто-то мог объяснить мне более ясно, что я, вероятно, имел в виду, я был бы признателен!
glaebhoerl
(Также я думаю, что вы, возможно, включили ограничение постановки и уродливые кавычки.)
glaebhoerl
1
Doh! Спасибо что подметил это! Исправлена. Да, недисциплинированный, вероятно, был бы лучшим способом выразить это. Я думаю, что различие здесь действительно между «встроенными» и, следовательно, «хорошо понятными» механизмами абстракции, в отличие от «специальных», или определяемых пользователем механизмов абстракции. Полагаю, я имею в виду, что вы могли бы определить библиотеку TH, в которой реализовано нечто, похожее на диспетчеризацию классов типов (хотя во время компиляции, а не во время выполнения)
mgsloan
8

Одна довольно прагматичная проблема с шаблоном Haskell состоит в том, что он работает только тогда, когда доступен интерпретатор байт-кода GHC, что не имеет место на всех архитектурах. Поэтому, если ваша программа использует Template Haskell или использует библиотеки, которые его используют, она не будет работать на компьютерах с процессором ARM, MIPS, S390 или PowerPC.

На практике это актуально: git-annex - это инструмент, написанный на Haskell, который имеет смысл запускать на машинах, которые беспокоятся о хранилище, такие машины часто имеют не i386-CPU. Лично я запускаю git-Annex на NSLU 2 (32 МБ ОЗУ, процессор 266 МГц; знаете ли вы, что Haskell отлично работает на таком оборудовании?) Если он будет использовать Template Haskell, это невозможно.

(Ситуация с GHC на ARM в наши дни значительно улучшается, и я думаю, что 7.4.2 даже работает, но точка зрения остается неизменной)

Иоахим Брейтнер
источник
1
«Шаблон Haskell использует встроенный компилятор и интерпретатор байт-кода GHC для запуска выражений сращивания». - haskell.org/ghc/docs/7.6.2/html/users_guide/…
Иоахим Брейтнер
2
ах, я это - нет, TH не будет работать без интерпретатора байт-кода, но это отличается от (хотя и имеет отношение к) ghci. Я не удивлюсь, если бы была идеальная связь между доступностью ghci и доступностью интерпретатора байт-кода, учитывая, что ghci зависит от интерпретатора байт-кода, но проблема заключается в отсутствии интерпретатора байт-кода, а не в отсутствии ghci в частности.
Мухмухтен
1
(кстати, у ghci забавно плохая поддержка интерактивного использования TH. try ghci -XTemplateHaskell <<< '$(do Language.Haskell.TH.runIO $ (System.Random.randomIO :: IO Int) >>= print; [| 1 |] )')
muhmuhten
Хорошо, с ghci я имел в виду способность GHC интерпретировать (вместо компиляции) код, независимо от того, поступает ли код интерактивно в двоичном файле ghci или из TH-соединения.
Иоахим Брейтнер
6

Почему TH плох? Для меня все сводится к следующему:

Если вам нужно создать столько повторяющегося кода, что вы пытаетесь использовать TH для его автоматической генерации, вы делаете это неправильно!

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

Иногда, конечно, это необходимо. Но иногда вы можете избежать необходимости TH, просто будучи немного умнее со своими проектами.

(Другое дело, что TH довольно низкоуровневый. Великолепного высокоуровневого дизайна нет; многие детали внутренней реализации GHC раскрыты. И это делает API склонным к изменениям ...)

MathematicalOrchid
источник
Я не думаю, что это означает, что ваш язык или приложение подвело вас, особенно если мы рассматриваем QuasiQuotes. Когда дело доходит до синтаксиса, всегда есть компромиссы. Некоторый синтаксис лучше описывает определенный домен, поэтому вы хотите иногда иметь возможность переключаться на другой синтаксис. QuasiQuotes позволяют элегантно переключаться между синтаксисами. Это очень мощный инструмент, который используется Yesod и другими приложениями. Возможность писать код генерации HTML с использованием синтаксиса, похожего на HTML, - удивительная особенность.
CoolCodeBro
@CoolCodeBro Да, квазицитирование довольно приятно, и я полагаю, немного ортогонально к TH. (Очевидно, это реализовано поверх TH.) Я больше думал об использовании TH для генерации экземпляров классов, или для создания функций из нескольких массивов, или чего-то в этом роде.
Математическая