即使没有扩展名ExistentialQuantification
,Haskell也支持一些存在类型,通过类型同构,适用于任何类型类C
,
(forall a. C a => (a -> b)) ~ ((exists a. C a => a) -> b)
因此函数f :: C a => a -> b
需要x
类型的参数exists a. C a
。但是Haskell不允许对某些类型的x
模式匹配C
(通过一个匹配的_
完成,因为类型类通常是无限的。)
这很奇怪,因为存在类型是广义和类型。 Haskell支持使用data
关键字的有限和类型,并允许它们的模式匹配。在C ++,Java和C#等语言中,存在类型是接口,它们支持与dynamic_cast
或instanceof
等关键字进行模式匹配。
为什么Haskell没有为上面的f
等函数实现模式匹配?
答案 0 :(得分:8)
Haskell的设计允许类型擦除实现。我们仍然可以运行Haskell而无需在运行时携带所有类型级别的信息。这允许实现减少内存占用。
请注意,程序员仍然可以通过添加Typeable a
约束来选择在运行时保留类型信息。然后可以使用cast
来模式匹配类型。
此外,无法在运行时对类型执行模式匹配对于保证parametricity / free theorems非常重要。例如,如果我们有多态函数
f :: forall a. a -> a
我们保证f
是身份(或无法终止)。这是因为任何此类f
必须是自然转换,除了身份之外没有其他选项可用。如果我们可以写
f x = if a==Int then x+1 else x
如果我们添加Typeable a
。
同样,g :: a->a->a
必须是投影,而h :: [a]->[a]
无法将[True]
发送至[False,True]
。此外,如果h [1,2]=[2,2,1]
则必须h "ab" = "bba"
。根据自然性,这些函数必须“统一”地处理所有类型a
。
答案 1 :(得分:2)
如果你想对类型进行模式匹配,那是不可能的,因为
有无数种类型可供匹配,因此您的模式永远不会详尽无遗。
作为一个实现细节,GHC在编译时擦除所有类型信息,因此无论如何都无法实现。 (这可能是由于第1点。)
您提到OO语言通常具有类似instanceof
运算符的功能。您可以使用Typeable
类在Haskell中执行此操作。如果某个类型是Typeable
的实例,则可以使用Dynamic
将其“转换”为toDyn
类型。然后,您可以稍后尝试使用fromDynamic
将其强制转换,然后返回Maybe
。 (或fromDyn
,返回默认值。)因此Dynamic
类型类似于Java的Object
;它可以是任何。通常情况下,这并不是非常严格的限制,通常你不会在Haskell中看到这种编程。
您还可以使用GADT来表示有限类型的集合,然后您可以将它们进行模式匹配。或者常规数据结构。