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

能否在Template Haskell的[d|…|]声明引号中获取Haddock注释?

如何在Template Haskell函数中访问声明引号内的Haddock注释?

当我们通过声明引号[d| ... |]将带Haddock注释的代码传给Template Haskell函数时,比如:

someTHFunction
  [d|
    -- | Some documentation
    data SomeType = SomeConstructor | SomeOtherConstructor
    |]

能否在函数内部拿到Some documentation这段注释?

遇到的问题

尝试通过DataD中的类型名称调用getDoc时,会触发如下报错:

Example.hs:(7,1)-(11,6): error: [GHC-24922] …
    ‘SomeType_0’ is not in scope at a reify

比如下面这个简单的恒等函数,它尝试用getDoc获取注释:

{-# LANGUAGE TemplateHaskell #-}

module SomeTHModule where

import Language.Haskell.TH

someTHFunction :: DecsQ -> DecsQ
someTHFunction decsq = do
  decs <- decsq
  let names = [name | DataD _ name _ _ _ _ <- decs]
  _ <- traverse (getDoc . DeclDoc) names
  pure decs

在其他模块调用时就会触发上述错误:

{-# LANGUAGE TemplateHaskell #-}

module Example where

import SomeTHModule

someTHFunction
  [d|
    -- | Some documentation
    data SomeType = SomeConstructor | SomeOtherConstructor
    |]

原因分析

报错的核心问题是:声明引号[d| ... |]生成的定义是临时的、未被GHC正式纳入模块作用域的绑定,GHC会自动给这些临时名称加上后缀(比如_0)。而getDoc底层依赖reify函数,reify只能查询已经被GHC处理并加入作用域的名称,自然找不到这些临时名称。

解决方案

不需要通过getDoc查询,直接从Dec的AST结构中提取注释即可。因为[d| ... |]生成的DataD构造器里,第一个参数就是Maybe Doc类型的Haddock注释(如果有的话)。

修改后的函数示例:

{-# LANGUAGE TemplateHaskell #-}

module SomeTHModule where

import Language.Haskell.TH
import Language.Haskell.TH.Syntax (Doc)

someTHFunction :: DecsQ -> DecsQ
someTHFunction decsq = do
  decs <- decsq
  -- 直接从DataD的AST中提取Haddock注释
  let docComments = [doc | DataD (Just doc) _ _ _ _ _ <- decs]
  -- 可根据需求处理注释,比如打印输出
  traverse_ (liftIO . print) docComments
  pure decs

这样修改后,就能直接获取到声明引号内的Haddock注释,完全避开了reify带来的作用域问题。

内容的提问来源于stack exchange,提问作者Antal Spector-Zabusky

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 12:06:02