haskell - Template Haskell 阶段限制的问题

标签 haskell template-haskell

我刚刚开始学习 Template Haskell,并陷入了简单的拼接问题。
在一个模块中,我实现了函数 tupleN ,它回复元组的第 N 个元素:

tupleN :: Lift a => a -> Int -> Q Exp
tupleN a n = do
   (TupE as) <- lift a
   return $ as !! n

在主模块中我有:

main :: IO ()
main = do
   let tup = (1::Int,'a',"hello")
   putStrLn $ show $(tupleN $tup 1)

这似乎有效,但事实并非如此。编译器打印错误:

GHC stage restriction: `tup'
  is used in a top-level splice or annotation,
  and must be imported, not defined locally
In the expression: tup
In the first argument of `tupleN', namely `$tup'
In the expression: tupleN ($tup) 1

如果我将元组描述直接放入拼接表达式中,代码就可以工作:

main :: IO ()
main = do
   putStrLn $ show $(tupleN (1::Int,'a',"hello") 1)

第一个变体我缺少什么?

最佳答案

您已尝试使用 tup作为拼接,但是 tup只是一个普通的值。您不想在其前面添加 $ 前缀.

此外,正如编译错误所述,由于 Template Haskell 在编译过程中运行,GHC 在完成当前模块的编译之前确实需要知道它在做什么。这意味着您的剪接表达式不能依赖于 tup ,因为仍在编译中。在拼接内部,您只能使用文字、导入的值和特殊的 'name''TypeName形式(我想你可以将其视为一种文字)。您可以使用以下命令从此汇编中获取一些信息: reify ,但即使这样也只能给你在编译时可用的数据——如果你想要一个函数,你可以传递用户输入,或从用户输入构造的数据,这是不可能的。

简而言之,您无法使用 Template Haskell 完全完成您想做的事情。但是,您可以定义一个扩展为函数的拼接来获取 i大小为 sz 的元组的第 个元素:

import Control.Monad (unless)
import Language.Haskell.TH

tupleN :: Int -> Int -> Q Exp
tupleN sz i = do
  unless (i < sz) . reportError $ "tupleN: index " ++ show i
    ++ " out of bounds for " ++ show sz ++ "-tuple"
  lamE
    [tupP (replicate i wildP
      ++ [varP (mkName "x")]
      ++ replicate (sz - i - 1) wildP)]
    (varE (mkName "x"))

关于haskell - Template Haskell 阶段限制的问题,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/14223610/

相关文章:

haskell - 描述给定 foldr 函数的前几个评估步骤

Haskell 解析 : `many` combinator inside an `optional` combinator

haskell - 如何规避 GHC 阶段限制?

c - 是否可以在运行时生成并运行 TemplateHaskell 生成的代码?

haskell - 我可以依靠 Template Haskell 扩展(使用 -ddump-splices)来始终生成有效代码吗?

haskell - 这是 Template Haskell 的预期行为吗?

haskell - 有没有办法在 haskell 中传递未知类型的运算符?

Haskell 循环函数

json - 防止 Aeson parseJSON 中的未知字段名称

haskell - Haskell 模板 - 静态断言