在Haskell中,类型在运行时并不存在。它们仅用于对源代码中的表达式进行分类,而不是运行时的值。
你当然可以使用
data JObject (className :: Symbol) = ...
,并使用它来强制确保只有某个特定Java类的对象才能使用某个函数,而不能给定一个不同类名的
JObject
。你甚至可以确保在多态上下文中,即使你不知道实际的类名是什么,也不会给定不匹配类的
JObject
来组合两个相同类的Java对象。但所有这些都是关于你的
代码的讨论。在运行时,当实际的
JObject
存在于内存中时,它根本不包含
className
。没有任何东西可以提取出来。
然而,有可能制作出一些具有将className
作为值而不是类型访问的效果的东西。你需要的是一个可以调用的函数,该函数以className
Symbol
为参数,将生成一个运行时的String
值。在Haskell中,为了使一个函数对类型参数的每个可能值具有不同的行为,通常使用类型类。你只需要一个带有给出String
值的方法的类,然后为每个实现该方法并返回相应String
的可能Symbol
创建一个实例。简单!
幸运的是,GHC实际上有一个内置类,其中包含了每个Symbol
的魔术实例,所以没有人需要手动编写所有这些实例。它被称为KnownSymbol
。方法symbolSing @s
实际上给你的是一个SSymbol s
而不是直接给你String
,但你可以通过调用fromSymbol
来获取它。
除了神奇地拥有无限数量的离散实例之外,KnownSymbol
类是一个完全普通的类。这意味着如果你只有一个类型参数化为未知Symbol
的情况下,你不能自动获得一个KnownSymbol
实例;你必须确保在函数中使用正确的约束条件,从选择Symbol
的地方流经KnownSymbol
实例,到你想要知道它是什么的地方。
SSymbol
类型是一种称为“单例”(不要与面向对象语言中的“单例模式”混淆)的技术示例。它意味着一个参数化类型,其值与类型参数的选择一一对应。例如,
SSymbol s
是每个
Symbol
s
选择的一个独立类型;每个类型只有一个值(因此称为“单例”),因此知道我们拥有的值可以揭示其对应的
Symbol
,即使在运行时
Symbol
实际上并不存在。使用这些单例类型作为链接可以提供比直接链接类型和值的类更多的选项,尽管在简单情况下并不一定需要。如果您感兴趣,
singletons
库 是一个更通用地定义和处理单例类型的框架(与由于需要编译器支持的“魔法实例”而提供的非常少数的单例类型不同)。