Я не очень по Template Haskell сам, но на основе моего ограниченного понимания проблемы в том, что three
в каком-то смысле «все еще определяется», когда GHC пытается скомпилировать $(findx three)
, в то время как все составные части из $(findx (Alpha "Four" 4))
являются уже полностью определены.
Основная проблема заключается в том, что все определения в одном модуле влияют на значение друг друга. Это связано с типом вывода, а также с взаимной рекурсией. Определение x = []
может означать множество разных вещей, в зависимости от контекста; он может быть привязан x
к списку Int
, или к списку IO()
, или что-нибудь еще. GHC, возможно, придется обработать весь модуль, чтобы выяснить, что именно это делает означает (или что это на самом деле ошибка).
Код, который Template Haskell испускает в модуль, который компилируется, должен быть рассмотрен этим анализом. Таким образом, код шаблона Haskell должен запускаться до GHC выяснил, что означают определения в модуле, и поэтому логически вы не можете использовать ни один из них.
Вещи, которые были импортированы из других модулей OTOH, были полностью проверены, когда GHC скомпилировал , что модуль. Нет больше информации, которую нужно узнать о них, скомпилировав этот модуль. Таким образом, они могут быть доступны и использованы до компиляции кода в этом модуле.
Другой способ подумать об этом: возможно, three
на самом деле не должен быть типа Alpha
. Возможно, это была опечатка, а конструктор должен был быть Alphz
. Обычно GHC узнает об этих типах ошибок, компилируя весь другой код в модуле, который использует three
, чтобы узнать, не вступает ли это в несогласованность или нет. Но что, если , что код использует или используется вещами, которые испускаются только $(findx three)
? Мы даже не знаем, какой код будет, пока мы его не запустим, но мы не можем решить вопрос о том, правильно ли набирается three
, пока мы его не запустим.
Возможно, это будет , чтобы снять это ограничение в некоторых случаях (я не знаю, было бы легко или практично). Возможно, мы могли бы заставить GHC считать, что что-то «определено раньше», если оно импортировано, или если оно использует только другие вещи, которые «определены раньше» (и, возможно, имеет явную подпись типа).Возможно, он мог бы попытаться скомпилировать модуль без запуска кода TH, и если ему удастся полностью выполнить typecheck three
, прежде чем он столкнется с какими-либо ошибками, он может передать это в код TH, а затем перекомпилировать все. Недостатком (помимо работы) было бы намного сложнее указать, какие точные ограничения касаются того, что вы можете передать шаблону Haskell.
Если вы просто пытаетесь сослаться на имя в том же модуле, что и определено, вы можете сделать это с кавычками/квазицитированием каким-то образом? Если вы пытаетесь на самом деле _execute_ что-то в сращивании, забудьте об этом. Компилятор принципиально не может этого сделать. – MathematicalOrchid
Хорошо. В чем разница между '$ (findx three)' и '$ (findx (Alpha" Four "4))'? Первое действительно приводит к ошибке, но последнее работает. – me2
'three' определяется в том же модуле, а' Alpha' - нет. – yiding