Если вы реорганизовать свой код следующим образом, он работает:
{-# LANGUAGE TemplateHaskell #-}
import Control.Lens
data None = None { _f :: Int }
type Simpl = Env
type Env = Int
makeLenses ''None
При использовании шаблона Haskell сращивания, чтобы добавить новые объявления верхнего уровня для вашего кода, как makeLenses
делает, порядок деклараций в вашем коде внезапно имеет значение!
Причина в том, что обычно компиляция программы Haskell предполагает сначала собирать все объявления верхнего уровня и переупорядочивать их внутренне, чтобы поместить их в порядок зависимостей, а затем скомпилировать их один за другим (или группу по группам для взаимно-рекурсивных объявлений) ,
С новыми декларациями, представленными путем запуска произвольного кода, поскольку GHC не знает, какие объявления makeLenses
могут потребоваться для запуска, а также он не знает, какие новые объявления он будет производить. Таким образом, он не может поместить весь файл в порядок зависимостей и просто отказаться от него и ожидает, что пользователь сделает это самостоятельно, по крайней мере, для решения вопроса о том, должны ли объявления проходить до или после сращивания.
только онлайн ссылки я могу найти, что объясняет это в original Template Haskell paper, раздел 7.2, где он говорит, что алгоритм:
- Group the declarations as follows:
[d1,...,da]
splice ea
[da+2,...,db]
splice eb
...
splice ez
[dz+2,...,dN]
where the only splice declarations are the ones indicated explicitly, so that each group [d1,...,da]
, etc, are all ordinary Haskell declarations.
- Perform conventional dependency analysis, followed by type checking, on the first group. All its free variables should be in scope.
Таким образом, проблема здесь в том, что первая группа объявлений перед сращиванием обрабатывается отдельно во вторую группу после сращивания, и она не может видеть определение Env
.
Мое общее эмпирическое правило заключается в том, чтобы поместить такие сращивания, как это, в нижней части файла, но я не думаю, что это гарантировано, что это всегда будет работать.
Это определенно странно. Я проверил с помощью '-ddump-splices' после помещения' Simpl' и 'Env' рядом друг с другом, и если бы я вручную вставлял их между ними, у него не было ошибки. Не исключено, что TH изменит масштаб, это, вероятно, либо ошибка в библиотеке Control.Lens.TH, либо что-то странное в том, как GHC обрабатывает TH-сращивания. – bheklilr
Компиляция с '-ddump-splices' не вносит никаких изменений и что вы подразумеваете под' вручную insert'? @bheklilr – IruT
Я изменил определения 'Simpl' и' Env' так, чтобы они были рядом друг с другом, а затем скомпилированы с помощью '-ddump-splices'. Затем я взял этот вывод и вложил его в файл между определениями 'Simpl' и' Env' и удалил 'makeLenses '' None'. Он скомпилирован просто отлично, так что это, безусловно, сам шаблон haskell, который делает это. – bheklilr