模板Haskell可以找出在类型类中声明的相关类型同义词的名称和/或声明吗?我曾期望reify
会做我想做的事,但似乎并没有提供所有必要的信息。它适用于获取函数类型签名:
% ghci
GHCi, version 7.8.3: http://www.haskell.org/ghc/ :? for help
...
Prelude> -- I'll be inserting line breaks and whitespace for clarity
Prelude> -- in all GHCi output.
Prelude> :set -XTemplateHaskell
Prelude> import Language.Haskell.TH
Prelude Language.Haskell.TH> class C a where f :: a -> Int
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C)
ClassI (ClassD [] Ghci1.C [PlainTV a_1627398388] []
[SigD Ghci1.f
(ForallT [PlainTV a_1627398388]
[ClassP Ghci1.C [VarT a_1627398388]]
(AppT (AppT ArrowT (VarT a_1627398388))
(ConT GHC.Types.Int)))])
[]
但是,向类添加关联的类型同义词不会导致输出更改(直到重命名):
Prelude Language.Haskell.TH> :set -XTypeFamilies
Prelude Language.Haskell.TH> class C' a where type F a :: * ; f' :: a -> Int
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C')
ClassI (ClassD [] Ghci3.C' [PlainTV a_1627405973] []
[SigD Ghci3.f'
(ForallT [PlainTV a_1627405973]
[ClassP Ghci3.C' [VarT a_1627405973]]
(AppT (AppT ArrowT (VarT a_1627405973))
(ConT GHC.Types.Int)))])
[]
如果知道的名称F
,则可以查找有关它的信息:
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''F)
FamilyI (FamilyD TypeFam
Ghci3.F
[PlainTV a_1627405973]
(Just StarT))
[]
但是我一开始找不到名字F
。即使我添加了类型类的实例,InstanceD
也没有关于定义的信息:
Prelude Language.Haskell.TH> instance C' [a] where type F [a] = a ; f' = length
Prelude Language.Haskell.TH> f' "Haskell"
7
Prelude Language.Haskell.TH> 42 :: F [Integer]
42
Prelude Language.Haskell.TH> putStrLn $(stringE . show =<< reify ''C')
ClassI (ClassD [] Ghci3.C' [PlainTV a_1627405973] []
[SigD Ghci3.f'
(ForallT [PlainTV a_1627405973]
[ClassP Ghci3.C' [VarT a_1627405973]]
(AppT (AppT ArrowT (VarT a_1627405973))
(ConT GHC.Types.Int)))])
[InstanceD []
(AppT (ConT Ghci3.C')
(AppT ListT (VarT a_1627406161)))
[]]
如果reify
不起作用,除了手动列出关联类型同义词以外,还有其他解决方法吗?
GHC 7.8.3的模板-haskell软件包的版本2.9.0.0中存在此问题。它也出现在GHC 7.4.2中,带有template-haskell软件包的2.7.0.0版。(我没有检查GHC 7.6。*,但我想它也在那里。)我对任何版本的GHC(包括“仅在GHC版本V中已修复”的解决方案)感兴趣。
@Kwarrtz:我现在才尝试。但是,它不起作用。它只会产生
—
Antal Spector-Zabusky
InstanceD
与我看到的相同的reify
:putStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])
计算为[InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []]
,缺少类型族实例。
我觉得很奇怪,
—
Kwarrtz
reify
没有返回必要的信息。也许show
正在隐藏一些信息?您是否尝试过Info
直接检查对象?
@Kwarrtz:我怕
—
Antal Spector-Zabusky
Info
的Show
实例只是派生的一个,和同为Show
实例Dec
。但是,我也可以按照您的要求直接检查,而没有:putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")
产生just a SigD
–这实际上[Dec]
是ClassD
!中唯一的内容。(要求LambdaCase
)。我同意这很奇怪。这就是为什么我问这个问题的原因:-)
@Abel:我认为我们已经达成了暴力协议–您的原始评论说,这还不足以吸引一个绝妙的主意,但确实吸引了Yuras的答案!我绝对同意一个好的答案是:-)
—
Antal Spector-Zabusky 2015年
reifyInstances
吗?