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

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

Template Haskell listed under "The Ugly (but necessary)" in response to the question Which Haskell (GHC) extensions should users use/avoid? Template Haskell considered a temporary/inferior solution in Unboxed Vectors of newtype'd values thread (libraries mailing list) Yesod is often criticized for relying too much on Template Haskell (see the blog post in response to this sentiment)

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

 Gabriel Gonzalez02 июн. 2012 г., 01:25
@ ErikPhilips Почему вы не позволяете людям, которые часто посещают этот тег, решать, принадлежит ли он здесь? Похоже, что ваше единственное взаимодействие с сообществом Haskell - это задавать вопросы.
 György Andrasek02 июн. 2012 г., 05:02
Голосование, чтобы открыть. Тот факт, что это вопрос более высокого уровня, не означает, что он не очень хороший.
 Dan Burton02 июн. 2012 г., 03:02
@ ErikPhilips Аспект механизма рекомендаций не имеет отношения к этому вопросу, потому что вы заметите, что это относится к решению между различными инструментами (например, «скажите мне, какой язык мне следует использовать»). Напротив, я просто прошу объяснений, касающихся конкретно шаблона Haskell, и в FAQ говорится: «Если вы мотивируете себя тем, что« я бы хотел, чтобы другие объяснили [пусто] мне », то вы, вероятно, в порядке». Сравните с, например, GOTO все еще считают вредным?
 Dan Burton01 июн. 2012 г., 22:45
Я не согласен с решением переехать; Я задаю этот вопрос в том же духе, что и Что плохого в ленивом вводе / выводе? и я ожидаю увидеть ответы так же. Я открыт для переписывания вопроса, поможет ли это.
 Erik Philips02 июн. 2012 г., 02:10
@ GabrielGonzalez очевидно из текущего вопроса и ответа, что он не следует заВОПРОСЫ-ОТВЕТ по какому вопросу я не должен задавать здесь: нет актуальной проблемы, которую нужно решить. Вопрос не решает специфическую для кода проблему и носит только концептуальный характер. И на основании вопроса Должен ли я избегать шаблона haskell тоже это падает вStack Overflow не является механизмом рекомендаций.

Ответы на вопрос(6)

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

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

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

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

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

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

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

Это беспринципно, если ты делаешь с ним беспринципные вещи. Единственное отличие состоит в том, что с компилятором, реализованным в механизмах абстракции, вы получаете больше уверенности в том, что абстракция не является утечкой. Возможно, демократизация языкового дизайна звучит немного страшно! Создатели библиотек TH должны хорошо документировать и четко определять значение и результаты инструментов, которые они предоставляют. Хорошим примером принципиального TH является производный пакет:http: //hackage.haskell.org/package/deriv - он использует 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 - это мощный инструмент, который может позволить вам / делать / почти все. Анархия! Что ж, по моему мнению, эта мощь может позволить вам преодолеть большинство его ограничений и создавать системы, способные к совершенно принципиальным подходам метапрограммирования. Стоит использовать уродливые хаки для имитации «правильной» реализации, так как постепенно дизайн «правильной» реализации станет понятен.

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

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

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

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

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

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

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

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

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

 glaebhoerl06 июн. 2012 г., 18:09
(Кроме того, я думаю, что вы, возможно, изменили ограничение постановки и уродливые кавычки.)
 mgsloan06 июн. 2012 г., 16:31
Это верно. Я пытался прояснить, о чем идет речь, несмотря на. Возможно я отредактирую, чтобы встроить точки illisuis.
 Ben Millwood06 июн. 2012 г., 15:44
Этот ответ сам по себе не очень хорош: вы делаете несколько ссылок на другой ответ, который мне нужно найти и найти, прежде чем я смогу правильно прочитать ваш.
 glaebhoerl06 июн. 2012 г., 18:03
Я должен сказать, что, возможно, «беспринципный» - более сильное слово, чем я должен был использовать, с некоторыми коннотациями, которые я не собирался - это, безусловно, не беспринципно! С этим пулевым пунктом у меня были самые большие проблемы, потому что у меня в голове было это чувство или не сформированная идея, и я не мог выразить это словами, а слово «беспринципный» было одним из слов, которые я уловил, и это было где-то поблизости. «Дисциплинированный», вероятно, ближе. Не имея четкой и лаконичной формулировки, я использовал несколько примеров. Если бы кто-то мог объяснить мне более ясно, что я, вероятно, имел в виду, я был бы признателен за это!
 mgsloan06 июн. 2012 г., 19:19
Doh! Спасибо что подметил это! Исправлена. Да, недисциплинированный, вероятно, был бы лучшим способом выразить это. Я думаю, что здесь действительно проводится различие между «встроенными» и, следовательно, «хорошо понятными» механизмами абстракции по сравнению со «специальными» или определяемыми пользователем механизмами абстракции. Я полагаю, что я имею в виду, что вы могли бы определить библиотеку TH, которая реализовала нечто, похожее на диспетчеризацию классов типов (хотя во время компиляции, а не во время выполнения)

которые поднимает dflemstr.

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

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

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

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

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

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

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

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

 Dan Burton21 июн. 2012 г., 04:44
Ты когда-нибудь писал свой контраргумент? Все еще жду вашей обещанной ссылки. Для тех, кто ищет старое содержание этого ответа: Stackoverflow.com / изменения / 10859441/1, а для тех, кто может просматривать удаленный контент: Stackoverflow.com / изменения / 10913718/6
 mgsloan01 мар. 2013 г., 11:35
@ aavogt tgeeky работал над исправлением, но я не думаю, что он закончил: Github.com / technogeeky / Нулевая Если никто этого не сделает / сделает что-то для этого, я в конце концов найду время.
 dflemstr02 июн. 2012 г., 17:48
Regarding Непрозрачность / монолитность: Можно, конечно, пройти через[Dec] и удалите ненужные вещи, но допустим, что функция читает внешний файл определения при генерации интерфейса JSON. Просто потому, что вы не используете этоDec не останавливает генератор при поиске файла определения, что приводит к сбою компиляции. По этой причине было бы неплохо иметь более ограниченную версиюQ монада, которая позволит вам генерировать новые имена (и тому подобное), но не позволяетIO, чтобы, как вы говорите, можно было отфильтровать его результаты / сделать другие композиции.
 mgsloan02 июн. 2012 г., 22:41
Я согласен, должна быть не-IO версия Q / цитата! Это также поможет решить - / Stackoverflow.com вопросы / 7107308 / .... Как только вы убедитесь, что код во время компиляции не делает ничего небезопасного, кажется, что вы можете просто запустить проверку безопасности в результирующем коде и убедиться, что он не ссылается на личные вещи.
 aavogt11 янв. 2013 г., 03:56
Есть ли более свежая версия Zeroth, чем та, что взломана? Последний (и репозиторий darcs) последний раз обновлялся в 2009 году. Обе копии не создаются с текущим ghc (7.6).

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

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

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

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

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

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

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

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

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

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

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

 Britton Kerin21 нояб. 2018 г., 23:15
«CPP имеет лучшее соотношение мощности к весу для тех проблем, которые он может решить». Верно. И в C99 он может решить все, что вы хотите. Учтите это: COS, Хао. Я также не понимаю, почему люди думают, что поколение AST лучше. Это просто больше двусмысленности и менее ортогонально к другим языковым особенностя

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

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

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

 muhmuhten18 июл. 2013 г., 03:52
... TH отлично работает без переводчика.
 Joachim Breitner18 июл. 2013 г., 22:05
Ладно, с ghci я имел в виду способность GHC интерпретировать (а не компилировать) код независимо от того, поступает ли он в интерактивном режиме в двоичном файле ghci или из соединения T
 Joachim Breitner18 июл. 2013 г., 09:02
«Шаблон Haskell использует встроенный компилятор и интерпретатор байт-кода GHC для запуска выражений соединения». - Haskell.org / GHC / документы / 7.6.2 / html / users_guide / ...
 muhmuhten18 июл. 2013 г., 18:15
(кстати, ghci забавно плохо поддерживает интерактивное использование TH. tryghci -XTemplateHaskell <<< '$(do Language.Haskell.TH.runIO $ (System.Random.randomIO :: IO Int) >>= print; [| 1 |] )')
 muhmuhten18 июл. 2013 г., 18:13
Да, я ... нет, TH не будет работать без интерпретатора байт-кода, но это отличается от (хотя и имеет отношение к) ghci. Я не удивлюсь, если бы была идеальная связь между доступностью ghci и доступностью интерпретатора байт-кода, учитывая, что ghci зависит от интерпретатора байт-кода, но проблема заключается в отсутствии интерпретатора байт-кода, а не в отсутствии ghci в частности.

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

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

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

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

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

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

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

TH также крайне опасен:

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

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

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

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

Opacity. Когда функция TH имеет типQ Dec, он может генерировать абсолютно все на верхнем уровне модуля, и у вас нет абсолютно никакого контроля над тем, что будет сгенерировано.Monolithism. Вы не можете контролировать, сколько генерирует функция TH, если разработчик не позволяет это; если вы найдете функцию, которая генерирует интерфейс базы данныха такж Интерфейс сериализации JSON, вы не можете сказать: «Нет, мне нужен только интерфейс базы данных, спасибо; я разверну свой собственный интерфейс JSON» Длительное время Код TH занимает относительно много времени для запуска. Код интерпретируется заново каждый раз, когда файл компилируется, и часто для выполнения загружаемого кода TH требуется тонна пакетов, которые необходимо загрузить. Это значительно замедляет время компиляции.
 mightybyte01 июн. 2012 г., 23:45
Добавьте к этому тот факт, что template-haskell исторически очень плохо документирован. (Хотя я только что посмотрел еще раз, и кажется, что сейчас, по крайней мере, немного лучше.) Кроме того, чтобы понять template-haskell, вам, по сути, нужно понимать грамматику языка Haskell, которая налагает определенную сложность (это не схема). Эти две вещи помогли мне преднамеренно не потрудиться понять TH, когда я был новичком в Haskell.
 Thomas M. DuBuisson01 июн. 2012 г., 23:45
Не забывайте, что использование шаблона Haskell означает, что порядок объявлений имеет значение! TH просто не так тесно интегрирован, как можно было бы надеяться, учитывая гладкую полировку Haskell (будь то 1.4, '98, 2010 или даже Глазго).
 augustss02 июн. 2012 г., 00:55
Вы можете рассуждать о Haskell без особых затруднений, такой гарантии нет по шаблону Haskell.
 Gabriel Gonzalez02 июн. 2012 г., 01:20
А что случилось с обещанием Олега о безопасной альтернативе TH? Я имею в виду его работу, основанную на его статье «Наконец, без тегов, частично оцененной» и других его заметкаВо. Это выглядело так многообещающе, когда они объявили об этом, и тогда я больше ни слова об этом не слышал.

Ваш ответ на вопрос