GHC阶段限制(模板Haskell)

4
我不明白为什么在以下代码中会出现“GHC阶段限制”:

import Language.Haskell.TH

rules :: [ExpQ]
rules = [ [| \a -> a |], [| \_ -> 1 |] ]

findTransforms :: Int -> [ExpQ] -> Bool
findTransforms _ [] = False
findTransforms e (r:rs) = if ($r e) == 1 then True else findTransforms e rs

如果代码没有做任何有用的事情也不要担心 - 它是为了清晰起见而提取的最小化示例混淆代码。

我不从拼接的代码中调用任何函数。 为什么需要阶段限制?

编辑1:已编辑以提供更简单的代码示例。


5
“obfuscated for clarity” 意为 “为了更清晰而模糊不清”(即有意通过模糊或隐藏一些信息来使内容更易理解)。 - Daniel Wagner
3个回答

2
这种方法失败的原因与你无法书写相同。
 eval :: ExpQ -> Int
 eval expr = $expr

因为它需要在运行时编译,所以这是不可行的。
一种解决方法是将findTransforms也变成编译时计算,通过返回嵌套if表达式的表达式来实现,而不是返回该表达式的值。
findTransforms :: Int -> [ExpQ] -> ExpQ
findTransforms _ []     = [| False |]
findTransforms e (r:rs) = [| if $r e == 1 then True else $(findTransforms e rs) |]

当然,这意味着当你想要使用它时,你将不得不进行拼接。

1
我不是Template Haskell的专家,但在我看来,对r ($r)的插入必须发生在编译时,因此r必须在编译时已知,但rfindTransforms的运行时参数。

0

阶段限制意味着您不能在定义它的同一模块中使用模板Haskell。如果您将其放入一个模块中并从另一个模块调用它,则应该没问题。

Dave4420是正确的,这与编译有关;您的模板Haskell必须在使用之前进行编译,因此必须在导入的模块中定义。 (这意味着ghc在编译模块时不需要额外的传递。)


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接