获取 Haskell 类型类中的实例列表
有没有一种方法可以以编程方式获取类型类的实例列表?
让我震惊的是,编译器必须知道这些信息才能进行类型检查和编译代码,因此有什么方法可以告诉编译器:嘿,你知道该类的那些实例,请在此处列出它们的列表(如字符串或它们的任何表示形式)。
Is there a way to programmatically get a list of instances of a type class?
It strikes me that the compiler must know this information in order to type check and compile the code, so is there some way to tell the compiler: hey, you know those instances of that class, please put a list of them right here (as strings or whatever some representation of them).
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(5)
您可以使用 Template Haskell 生成给定类型类范围内的实例。
在 GHCi 中运行:
另一个有用的技术是使用 GHCi 显示给定类型类范围内的所有实例。
编辑:要知道的重要一点是编译器只知道任何给定模块(或在 ghci 提示符等)范围内的类型类。因此,如果您在没有导入的情况下调用
showInstances
TH 函数,您将只能从 Prelude 中获取实例。如果您的范围内还有其他模块,例如 Data.Word,那么您也会看到所有这些实例。You can generate the instances in scope for a given type class using Template Haskell.
Running this in GHCi:
Another useful technique is showing all instances in scope for a given type class using GHCi.
Edit: The important thing to know is that the compiler is only aware of type classes in scope in any given module (or at the ghci prompt, etc.). So if you call the
showInstances
TH function with no imports, you'll only get instances from the Prelude. If you have other modules in scope, e.g. Data.Word, then you'll see all those instances too.请参阅模板 haskell 文档: http://hackage.haskell.org/packages/archive/template-haskell/2.5.0.0/doc/html/Language-Haskell-TH.html
使用
reify
,您可以获取一个信息记录,其中包含类的实例列表。您还可以直接使用isClassInstance
和classInstances
。See the template haskell documentation: http://hackage.haskell.org/packages/archive/template-haskell/2.5.0.0/doc/html/Language-Haskell-TH.html
Using
reify
, you can get an Info record, which for a class includes its list of instances. You can also useisClassInstance
andclassInstances
directly.一旦您获得实例声明
以及
单个具体实例(例如
instance Eq Bool
),这就会遇到很多问题。您将获得
Eq
的无限实例列表 -Bool
、[Bool]
、[[Bool]]
,[[[Bool]]]
等等,(Bool,Bool)
,((Bool,Bool),Bool)
,(((Bool,Bool),Bool),Bool)
等等,以及这些的各种组合,例如([((Bool,[Bool]),Bool)],Bool)
等等。目前尚不清楚如何在String
中表示这些;即使是TypeRep
列表也需要一些非常智能的枚举。编译器可以(尝试)推断出某个类型是否是任何给定类型的
Eq
实例,但它不会读取作用域中的所有实例声明,然后只是开始推断所有可能的实例,因为这永远不会结束!当然,重要的问题是,你需要这个做什么?
This is going to run into a lot of problems as soon as you get instance declarations like
and
along with a single concrete instance (e.g.
instance Eq Bool
).You'll get an infinite list of instances for
Eq
-Bool
,[Bool]
,[[Bool]]
,[[[Bool]]]
and so on,(Bool,Bool)
,((Bool,Bool),Bool)
,(((Bool,Bool),Bool),Bool)
etcetera, along with various combinations of these such as([((Bool,[Bool]),Bool)],Bool)
and so forth. It's not clear how to represent these in aString
; even a list ofTypeRep
would require some pretty smart enumeration.The compiler can (try to) deduce whether a type is an instance of
Eq
for any given type, but it doesn't read in all the instance declarations in scope and then just starts deducing all possible instances, since that will never finish!The important question is of course, what do you need this for?
我想,这是不可能的。我向您解释了类型类的实现(对于 GHC),从中您可以看到,编译器不需要知道哪些类型是类型类的实例。它只需要知道特定类型是否是实例。
类型类将被转换为数据类型。作为示例,让我们以
Eq
为例:类型类将被转换为一种字典,包含其所有功能:
然后,每个类型类约束将转换为包含字典的额外参数:
成为:
重要的事情也就是说,字典将在运行时传递。想象一下,您的项目包含许多模块。 GHC 不必检查所有模块的实例,它只需查找实例是否在任何地方定义。
但如果您有可用的源代码,我想对实例使用旧式的 grep 就足够了。
I guess, it's not possible. I explain you the implementation of typeclasses (for GHC), from it, you can see, that the compiler has no need to know which types are instance of a typeclass. It only has to know, whether a specific type is instance or not.
A typeclass will be translated into a datatype. As an example, let's take
Eq
:The typeclass will be translated into a kind of dictionary, containing all its functions:
Each typeclass constraint is then translated into an extra argument containing the dictionary:
becomes:
The important thing is, that the dictionary will be passed at runtime. Imagine, your project contains many modules. GHC doesn't have to check all the modules for instances, it just has to look up, whether an instance is defined anywhere.
But if you have the source available, I guess an old-style
grep
for the instances would be sufficient.对于现有的类,不可能自动执行此操作。对于您自己的类及其实例,您可以这样做。您需要通过 Template Haskell (或者可能是准引用)声明所有内容,它会自动生成一些奇怪的数据结构,对声明的实例进行编码。定义奇怪的数据结构并让 Template Haskell 执行此操作,这些细节留给有用例的人。
也许您可以在构建中添加一些 Template Haskell 或其他魔法,以将所有源文件作为运行时可用的文本包含在内(参见程序 quine)。然后你的程序将“grep 自身”...
It is not possible to automatically do this for existing classes. For your own class and instances thereof you could do it. You would need to declare everything via Template Haskell (or perhaps the quasi-quoting) and it would automatically generate some strange data structure that encodes the declared instances. Defining the strange data structure and making Template Haskell do this are details left to whomever has a use case for them.
Perhaps you could add some Template Haskell or other magic to your build to include all the source files as text available at run-time (c.f. program quine). Then your program would 'grep itself'...