获取Haskell中类型类中的实例列表

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,那么您也会看到所有这些实例.


scl*_*clv 7

请参阅模板haskell文档:http://hackage.haskell.org/packages/archive/template-haskell/2.5.0.0/doc/html/Language-Haskell-TH.html

使用reify,您可以获取一个Info记录,该记录包含一个类的实例列表.您也可以使用isClassInstanceclassInstances直接.


yat*_*975 6

一旦获得类似的实例声明,这将遇到很多问题

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任何给定类型的实例,但它不读取范围内的所有实例声明,然后开始推断所有可能的实例,因为它永远不会完成!

当然,重要的问题是,你需要做什么?