模板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 版本的 template-haskell 包中的版本 2.9.0.0 中;它也存在于 GHC 7.4.2 版本的 template-haskell 包中的版本 2.7.0.0 中。(我没有在 GHC 7.6.* 上检查,但我想它也存在这个问题。)我对任何版本的 GHC(包括“只有在 GHC 版本 V 中修复了此问题”)都感兴趣的解决方案。
reifyInstances
吗? - KwarrtzputStrLn $(stringE . show =<< reifyInstances''C'=<< sequence [[t | [Int] |]])
评估为[InstanceD [] (AppT (ConT Ghci1.C') (AppT ListT (VarT a_1627405978))) []]
,其中缺少类型族实例。 - Antal Spector-Zabuskyreify
不返回必要的信息有点奇怪。也许show
隐藏了部分信息?你试过直接检查Info
对象吗? - KwarrtzInfo
的Show
实例只是派生的,Dec
的Show
实例也是一样。不过,正如你所要求的那样,我也可以直接检查,结果是否定的:putStrLn $(reify ''C' >>= \i -> case i of ClassI (ClassD _ _ _ _ [SigD _ _]) _ -> stringE "just a SigD" ; _ -> stringE "something else")
会产生just a SigD
——这确实是ClassD
中唯一的[Dec]
!(需要LambdaCase
)。我同意这很奇怪;这就是我问这个问题的原因 :-) - Antal Spector-Zabusky