一个quasiquoter'使用'变量可以在它被调用的同一个文件中定义吗?

jcr*_*vao 1 haskell template-haskell

所以,我开始尝试quasiquotation和模板haskell.

我想修改一个现有的(大)准规则代码,同时使用在"被调用"的地方定义的变量的实际值.举一个简单的例子说明:

main.hs

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

import Language.Haskell.TH
import Exp02

x = "cde"

main = do
  putStrLn [str|$x|]
Run Code Online (Sandbox Code Playgroud)

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"
  }
Run Code Online (Sandbox Code Playgroud)

虽然这编译并打印出"cde",但这不是我想要的.我的理解是拼接后的主要代码是:putStrLn x.我想要的是生成putStrLn cde(我知道这不是有效的haskell代码,但它只是代表我的观点).

因此,换句话说,我不想' x在主文件中创建对变量的引用',我想在xptoquasiquoter代码中实际使用它的值.

我猜这可能是不可能的,因为它意味着main.hs和之间的循环引用Exp02.hs,因此面临TH阶段的限制.这是正确的,还是有办法在代码中使用x xpto

谢谢!

Dav*_*ani 6

不,你想要做的事情目前是不可能的.从模板haskell文档:

如果从另一个模块导入函数,则只能在编译时运行函数,该模块不是包含当前正在编译的模块的相互递归的模块组的一部分.此外,必须通过从要运行拼接的模块的非SOURCE导入来访问互相递归组的所有模块.

例如,在编译模块A时,如果B不直接或间接导入A,则只能运行从B导入的模板Haskell函数.原因应该是明确的:运行B我们必须编译并运行A,但我们目前正在进行类型检查A.

您正尝试x在编译时在x定义的同一模块中运行该函数(或更严格的值),这明确表示不允许.