2014-01-02 5 views
11

Этот код компилируется нормально:Haskell: Template Haskell и область

data None = None { _f :: Int } 
type Simpl = Env 

type Env = Int 

Однако я получил ошибку с этим кодом:

{-# LANGUAGE TemplateHaskell #-} 
import Control.Lens 

data None = None { _f :: Int } 

type Simpl = Env 

makeLenses ''None 

type Env = Int 

Ошибка:

Not in scope: type constructor or class `Env' 

I просто добавила одну строку makeLenses ''None между объявлениями типа.
Это означает, что код TemplateHaskell может изменить область конструктора типов?

Кто-нибудь знает подробности об этой проблеме (или как избежать этой проблемы)?

+0

Это определенно странно. Я проверил с помощью '-ddump-splices' после помещения' Simpl' и 'Env' рядом друг с другом, и если бы я вручную вставлял их между ними, у него не было ошибки. Не исключено, что TH изменит масштаб, это, вероятно, либо ошибка в библиотеке Control.Lens.TH, либо что-то странное в том, как GHC обрабатывает TH-сращивания. – bheklilr

+0

Компиляция с '-ddump-splices' не вносит никаких изменений и что вы подразумеваете под' вручную insert'? @bheklilr – IruT

+0

Я изменил определения 'Simpl' и' Env' так, чтобы они были рядом друг с другом, а затем скомпилированы с помощью '-ddump-splices'. Затем я взял этот вывод и вложил его в файл между определениями 'Simpl' и' Env' и удалил 'makeLenses '' None'. Он скомпилирован просто отлично, так что это, безусловно, сам шаблон haskell, который делает это. – bheklilr

ответ

13

Если вы реорганизовать свой код следующим образом, он работает:

{-# 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.

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

+0

Обычно я пытаюсь использовать TH в своем собственном модуле, если он не может быть линейно упорядочен вместе с существующими объявлениями. –

Смежные вопросы