2012-04-04 1 views
4

Квази-кавычки позволяют генерировать код АСТ во время компиляции, но он вставляет сгенерированный код в том месте, где была написана Quasi-quote. Можно ли каким-либо образом вставить код, сгенерированный компиляцией, в другое место? Например, в конкретных файлах модулей, отличных от тех, где была написана QQ? Это будет зависеть от жестко закодированной структуры модуля, но это нормально.Как включить код в разных местах во время компиляции в Haskell?

Если с QQ это невозможно, но кто-то знает другой способ его достижения, я открыт для предложений.

+4

Я думаю, было бы полезно, если бы вы могли упомянуть о том, чего вы пытаетесь достичь с этим. Технически TH может запускать произвольное IO, включая чтение и анализ компилируемого модуля, чтобы вы могли извлекать материал из разных мест или даже разных модулей, но детали зависят от того, что вы пытаетесь сделать. – hammar

ответ

4

Чтобы ответить на это, полезно знать, что такое квазициклер. Из GHC Documentation, квази-Quoter является значением

data QuasiQuoter = QuasiQuoter { quoteExp :: String -> Q Exp, 
           quotePat :: String -> Q Pat, 
           quoteType :: String -> Q Type, 
           quoteDec :: String -> Q [Dec] } 

То есть, это парсер из произвольной строки к одному или нескольким из ExpQ, PatQ, TypeQ и DecQ, которые Template Haskell представления выражений , шаблоны, типы и декларации соответственно.

Когда вы используете квазицитацию, GHC применяет синтаксический анализатор к String для создания ExpQ (или другого типа), а затем объединяет в полученное выражение haskell шаблона для получения фактического значения.

Похоже, что вы просите сделать раздельный синтаксический анализ и сплайсинг квазиквазота, чтобы у вас был доступ к выражению TH. Затем вы можете импортировать это выражение в другой модуль и объединить его там сами.

Зная тип квазициклера, легко понять, что это возможно. Обычно вы используете QQ, как

-- file Expr.hs 
eval :: Expr -> Integer 
expr = QuasiQuoter { quoteExp = parseExprExp, quotePat = parseExprPat } 

-- file Foo.hs 
import Expr 
myInt = eval [expr|1 + 2|] 

Вместо этого, вы можете извлечь анализатору самостоятельно, получить TH выражение, и сращивать его позже:

-- file Foo.hs 
import Expr 

-- run the QQ parser 
myInt_TH :: ExpQ 
myInt_TH = quoteExp expr "1 + 2" 

-- file Bar.hs 
import Foo.hs 

-- run the TH splice 
myInt = $(myInt_TH) 

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