Может ли квазицитатор «использовать» переменные, определенные в том же файле, в котором он вызывается?

Итак, я начинаю экспериментировать с квазицитатами и шаблонным haskell.

Я хочу изменить существующий (большой) код квазицитирования, используя фактическое значение переменной, определенной там, где она «вызывается». Чтобы проиллюстрировать на простом примере:

main.hs

{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}

import Language.Haskell.TH
import Exp02

x = "cde"

main = do
  putStrLn [str|$x|]

Exp02.hs

{-# LANGUAGE QuasiQuotes #-}
{-# LANGUAGE TemplateHaskell #-}

module Exp02 where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax
import Language.Haskell.TH.Quote

xpto :: String -> ExpQ
xpto [] = stringE []
xpto ('$':rest) = varE (mkName rest)
xpto str = stringE str

str = QuasiQuoter
  { quoteExp = xpto
  , quotePat = fail $ "patterns"
  , quoteType= fail $ "types"
  , quoteDec = fail $ "declarations"
  }

Пока это компилируется и выводит "cde", это не то, что я хочу. Насколько я понимаю, результирующий код в main после сплайсинга: putStrLn x. Я хочу сгенерировать putStrLn cde (я знаю, что это недействительный код haskell, но это просто для представления моей точки зрения).

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

Я предполагаю, что это может быть невозможно, поскольку это будет означать циклическую ссылку между main.hs и Exp02.hs и, таким образом, столкнуться с ограничением этапа TH. Это правильно или есть способ использовать x value внутри кода xpto?

Спасибо!


person jcristovao    schedule 20.09.2013    source источник


Ответы (1)


Нет, то, что вы пытаетесь сделать, в настоящее время невозможно. Из документов по шаблону haskell:

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

Например, при компиляции модуля A вы можете запускать функции Template Haskell, импортированные из B, только если B не импортирует A (прямо или косвенно). Причина должна быть ясна: для запуска B мы должны скомпилировать и запустить A, но в настоящее время мы проверяем тип A.

Вы пытаетесь запустить функцию (или, точнее, значение) x во время компиляции в том же модуле, что и x, что явно запрещено.

person David Miani    schedule 20.09.2013