使用模板Haskell获取关联的类型同义词


257

模板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中已修复”的解决方案)感兴趣。


2
你看了reifyInstances吗?
Kwarrtz

2
@Kwarrtz:我现在才尝试。但是,它不起作用。它只会产生InstanceD与我看到的相同的reifyputStrLn $(stringE . show =<< reifyInstances ''C' =<< sequence [[t|[Int]|]])计算为[InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []],缺少类型族实例。
Antal Spector-Zabusky

1
我觉得很奇怪,reify没有返回必要的信息。也许show正在隐藏一些信息?您是否尝试过Info直接检查对象?
Kwarrtz

@Kwarrtz:我怕InfoShow实例只是派生的一个,和同为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)。我同意这很奇怪。这就是为什么我问这个问题的原因:-)
Antal Spector-Zabusky

1
@Abel:我认为我们已经达成了暴力协议–您的原始评论说,这还不足以吸引一个绝妙的主意,但确实吸引了Yuras的答案!我绝对同意一个好的答案是:-)
Antal Spector-Zabusky 2015年

Answers:


15

由于没有人要求,因此未实现。

奇怪的是,TH使用了自己的AST,但它没有遵循内部编译器的AST。结果,任何新功能(例如,关联的类型系列)都无法通过TH自动获得。有些人必须打开票证并执行它。

作为参考:内部reifyClass函数将忽略关联的类型族(这是返回的元组的第5个元素classExtraBigSig,另请参见的定义ClassATItem。)

从技术上讲,应该很容易在中实现关联的类型家族支持reify,但是很可能它将需要TH API中向后不兼容的更改,例如,因为其AST似乎不支持关联的类型默认值。

补充:现在已实现(无需更改API,但可以在下一ghc发行版中使用)。


1
@ AntalS-Z我的意思是FamilyD不支持关联的类型同义词defaults。您可能没有使用它们,但是完整的解决方案可能需要更改API。
Yuras

5
@Abel,将赏金开放到最后也往往有助于良好答案吸引选票,因此,与快速授予奖励相比,这是奖励良好答案的更有效方法。
dfeuer

1
赏金期已过。这是最好的(也是唯一的)答案,直到或除非问题报告#10891被解决。在您的答案中包含指向错误报告的链接也许是个好主意。
亚伯

1
仅供参考,#10891已修复,正在等待合并。
锡南2015年

1
@SwiftsNamesake AFAIK ghc开发人员希望在不破坏TH API的情况下自由更改内部AST。可能还有其他原因。
尤拉斯(Yuras)'17
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.