所以,我开始尝试使用quasiquotation和模板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”,但这不是我想要的。我的理解是拼接后的主要代码是:putStrLn x
。我想要的是生成putStrLn cde
(我知道这不是有效的haskell代码,但它只是代表我的观点)。
因此,换句话说,我不想'在主文件中创建对变量x
的引用',我想在xpto
quasiquoter中实际使用它的值代码。
我猜这可能是不可能的,因为它意味着main.hs
和Exp02.hs
之间的循环引用,因此面临TH阶段限制。这是正确的,还是有办法在xpto
代码中使用x 值?
谢谢!
答案 0 :(得分:6)
不,你目前要做的事情是不可能的。来自template haskell docs:
如果从另一个模块导入函数,则只能在编译时运行函数,该模块不是包含当前正在编译的模块的相互递归的模块组的一部分。此外,必须通过从要运行拼接的模块的非SOURCE导入来访问相互递归组的所有模块。
例如,在编译模块A时,如果B不直接或间接导入A,则只能运行从B导入的模板Haskell函数。原因应该是明确的:运行B我们必须编译并运行A,但我们目前正在对A进行类型检查。
您正在尝试在编译时在x
定义的同一模块中运行该函数(或更严格的值)x
,这显然是不允许的。