有全称量化的类型变量,也有存在量化的数据类型。然而,尽管人们有时会提供伪代码形式的exists a. Int -> a
来帮助解释概念,但似乎编译器扩展并没有任何真正感兴趣的地方。这只是一种“增加这个没有太多价值”的事情(因为对我来说似乎很有价值),还是像不可判定性那样存在问题,使其真正不可能。
编辑: 我将viorior的答案标记为正确答案,因为这似乎是没有包括它的实际原因。但是,为了防止有人想要进一步澄清这一点,我想添加一些额外的评论。
根据评论的要求,我将举一个例子,说明为什么我认为这很有用。假设我们有一个如下所示的数据类型:
data Person a = Person
{ age: Int
, height: Double
, weight: Int
, name: a
}
因此,我们选择对a
进行参数化,这是一种命名约定(我知道在这个例子中创建一个包含“first,middle,last”等适当数据结构的“NamingConvention”ADT可能更有意义,以适应美国人的惯用法和墨西哥裔的“name,paternal name,maternal name”等,但现在就这样吧)。
因此,有几个函数基本上忽略了Person所参数化的类型。例如:
age :: Person a -> Int
height :: Person a -> Double
weight :: Person a -> Int
并且任何基于这些构建的函数都可以忽略a
类型。例如:
atRiskForDiabetes :: Person a -> Bool
atRiskForDiabetes p = age p + weight p > 200
--Clearly, I am not actually a doctor
现在,如果我们有一个由不同类型的人组成的列表(类型为[exists a. Person a]
),我们希望能够将一些函数映射到该列表上。当然,存在一些无用的映射方式:
heteroList :: [exists a. Person a]
heteroList = [Person 20 30.0 170 "Bob Jones", Person 50 32.0 140 3451115332]
extractedNames = map name heteroList
在这个例子中,extractedNames
当然是没用的,因为它的类型是 [exists a. a]
。但是,如果我们使用了其他函数:totalWeight :: [exists a. Person a] -> Int
totalWeight = sum . map age
numberAtRisk :: [exists a. Person a] -> Int
numberAtRisk = length . filter id . map atRiskForDiabetes
现在,我们有了一个可以处理异构集合的有用工具(而且,我们甚至没有涉及到类型类)。请注意,我们能够重复使用现有的函数。使用存在类型将如下所示:
data SomePerson = forall a. SomePerson (Person a) --fixed, thanks viorior
但是现在,我们如何使用age
和atRiskForDiabetes
?我们无法这样做。我认为你需要像这样做:
someAge :: SomePerson -> Int
someAge (SomePerson p) = age p
这真的很糟糕,因为你必须为新类型重写所有组合器。如果你想对一个参数化了多个类型变量的数据类型进行操作,情况会更加糟糕。想象一下:
somewhatHeteroPipeList :: forall a b. [exists c d. Pipe a b c d]
我不会进一步解释这个思路,但请注意,如果仅使用存在数据类型来做任何类似此操作,您将需要重写许多组合器。
话虽如此,希望我已经给出了一个稍微有说服力的用例。如果它看起来没有用(或者示例似乎过于人为),请随时告诉我。另外,由于我首先是一个程序员,而没有接受过类型理论方面的培训,所以很难看到如何在这里应用斯科勒定理(如viorior发布的)。如果有人能向我展示如何将其应用于我提供的Person a
示例,我将非常感激。谢谢。
data Exists t = forall a. Exists (t a)
work? In your case you'd writefoo :: Exists ((->) Int)
. We do have existentials in this sense, just bounded by a data constructor.”这句话的意思是:“data Exists t = forall a. Exists (t a)
这个语法结构是否可用?在你的情况下,你会写成foo :: Exists ((->) Int)
。我们确实有这种存在类型,只是被一个数据构造器所限制。” - daniel gratzer