在Template Haskell实例中reify类方法报错,如何正确引用?
在类实例中通过Template Haskell引用类方法时的
reify错误解决 我定义了Cls类,在它的Evaluate实例的+.方法中,尝试用Template Haskell的reify做代码分析,但调用$(typesOf '(+.))时出现错误:
‘+.’ is not in the type environment at a reify In the untyped splice: $(typesOf '(+.))
我怀疑'(+.))解析到了当前实例声明中的函数,而非类声明里的+.方法,这个判断对吗?如果正确,怎么在实例里把类方法正确传给Template Haskell?
完整代码
Main模块
{-# LANGUAGE TemplateHaskell #-} module Main where import Th import Debug.Trace (trace) import Data.List (intercalate) class Cls a where infixl 6 +. (+.) :: Num a => v a -> v a -> v a newtype Evaluate a = Evaluate a instance Cls Evaluate where (+.) a b = doSomething $(typesOf '(+.)) a b -- 以下代码无关紧要 doSomething :: [String] -> a -> a doSomething types a _ = trace (intercalate ", " types) a main :: IO () main = putStrLn "Hello, Haskell!"
(注:原代码缺少trace和intercalate的导入,这里补上以保证可编译)
Th模块
{-# LANGUAGE TemplateHaskell #-} module Th where import Language.Haskell.TH typesOf :: Name -> Q Exp typesOf name = do _ <- reify name -- 后续逻辑 [e|["a", "b"]|]
问题分析
你的判断是对的。在实例声明的作用域里,+.会优先绑定到当前正在定义的实例实现上,而这个实例方法还处于编译过程中,尚未进入全局类型环境,所以reify找不到它,导致报错。
解决办法
1. 用类名限定指定类方法
直接在TH引用中加上类名前缀,明确指定要引用的是Cls类中的+.方法,避开局部作用域的名称绑定:
instance Cls Evaluate where (+.) a b = doSomething $(typesOf '(Cls.+.)) a b
这是最直接的方式,让TH正确解析到类的方法名称。
2. 为类方法定义别名
在类定义时,给+.绑定一个普通标识符作为别名,后续TH直接引用这个别名:
class Cls a where infixl 6 +. (+.) :: Num a => v a -> v a -> v a plusDot = (+.) -- 定义类方法的别名
然后在实例中引用别名:
instance Cls Evaluate where (+.) a b = doSomething $(typesOf 'plusDot) a b
这种方式适合需要多次引用类方法的场景,避免重复写限定名称。
内容的提问来源于stack exchange,提问作者Niek Janssen
相关产品推荐
相关产品推荐

