能否在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
相关产品推荐
相关产品推荐

