men*_*ics 17 haskell introspection
有没有办法以编程方式获取类型类的实例列表?
让我觉得编译器必须知道这些信息才能输入检查和编译代码,所以有没有办法告诉编译器:嘿,你知道那个类的实例,请在这里列出它们(如字符串或其他任何表示形式).
Joh*_*n L 13
您可以使用Template Haskell在给定类型类的范围内生成实例.
import Language.Haskell.TH
-- get a list of instances
getInstances :: Name -> Q [ClassInstance]
getInstances typ = do
ClassI _ instances <- reify typ
return instances
-- convert the list of instances into an Exp so they can be displayed in GHCi
showInstances :: Name -> Q Exp
showInstances typ = do
ins <- getInstances typ
return . LitE . stringL $ show ins
Run Code Online (Sandbox Code Playgroud)
在GHCi中运行:
*Main> $(showInstances ''Num)
"[ClassInstance {ci_dfun = GHC.Num.$fNumInteger, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Integer.Type.Integer]},ClassInstance {ci_dfun = GHC.Num.$fNumInt, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Types.Int]},ClassInstance {ci_dfun = GHC.Float.$fNumFloat, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Types.Float]},ClassInstance {ci_dfun = GHC.Float.$fNumDouble, ci_tvs = [], ci_cxt = [], ci_cls = GHC.Num.Num, ci_tys = [ConT GHC.Types.Double]}]"
Run Code Online (Sandbox Code Playgroud)
另一个有用的技术是使用GHCi显示给定类型类的范围内的所有实例.
Prelude> :info Num
class (Eq a, Show a) => Num a where
(+) :: a -> a -> a
(*) :: a -> a -> a
(-) :: a -> a -> a
negate :: a -> a
abs :: a -> a
signum :: a -> a
fromInteger :: Integer -> a
-- Defined in GHC.Num
instance Num Integer -- Defined in GHC.Num
instance Num Int -- Defined in GHC.Num
instance Num Float -- Defined in GHC.Float
instance Num Double -- Defined in GHC.Float
Run Code Online (Sandbox Code Playgroud)
编辑:重要的是要知道编译器只知道任何给定模块(或ghci提示符等)中的作用域类型.因此,如果您在showInstances没有导入的情况下调用TH函数,则只能从Prelude中获取实例.如果您在范围内有其他模块,例如Data.Word,那么您也会看到所有这些实例.
请参阅模板haskell文档:http://hackage.haskell.org/packages/archive/template-haskell/2.5.0.0/doc/html/Language-Haskell-TH.html
使用reify,您可以获取一个Info记录,该记录包含一个类的实例列表.您也可以使用isClassInstance和classInstances直接.
一旦获得类似的实例声明,这将遇到很多问题
instance Eq a => Eq [a] where
[] == [] = True
(x:xs) == (y:ys) = x == y && xs == ys
_ == _ = False
Run Code Online (Sandbox Code Playgroud)
和
instance (Eq a,Eq b) => Eq (a,b) where
(a1,b1) == (a2,b2) = a1 == a2 && b1 == b2
Run Code Online (Sandbox Code Playgroud)
以及单个具体实例(例如instance Eq Bool).
你会得到实例的无限名单Eq- ,Bool,,[Bool] 等等,,,诸如此类,与这些这样的各种组合一起等等.目前还不清楚如何在一个; 甚至列表都需要一些非常聪明的枚举.[[Bool]][[[Bool]]](Bool,Bool)((Bool,Bool),Bool)(((Bool,Bool),Bool),Bool)([((Bool,[Bool]),Bool)],Bool)StringTypeRep
编译器可以(尝试)推断类型是否是Eq任何给定类型的实例,但它不读取范围内的所有实例声明,然后开始推断所有可能的实例,因为它永远不会完成!
当然,重要的问题是,你需要做什么?