You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.06.12 12:57:02