1

因此,我开始尝试使用 quasiquotation 和模板 haskell。

我想修改现有的(大)准引用代码,同时使用在“调用”位置定义的变量的实际值。用一个简单的例子来说明:

主文件

{-# 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在主文件中创建对变量的引用”,我想在xptoquasiquoter 代码中实际使用它的值。

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

谢谢!

4

1 回答 1

6

不,你正在尝试做的事情目前是不可能的。从模板haskell docs

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

例如,在编译模块 A 时,如果 B 不导入 A(直接或间接),则只能运行从 B 导入的 Template Haskell 函数。原因应该很清楚:要运行 B,我们必须编译并运行 A,但我们目前正在对 A 进行类型检查。

您正在尝试x在编译时在与定义相同的模块中运行该函数(或更严格的值) x,这已明确声明是不允许的。

于 2013-09-20T09:50:58.837 回答