在逻辑(经典或直觉)中,公式
(exists x. p x) -> q
forall x. (p x -> q)
是等价的(注意q 不依赖于上面的x)。这可以用来用全称量化来表达存在量化,前提是存在存在于蕴涵的左侧。 (这里是经典的proof。)
在函数式编程中,您可以实现相同的目的。而不是写
-- Pseudo-Haskell follows
f :: (exists a. (a, a->Int)) -> Int
f (x,h) = h x
我们可以使用
-- Actual Haskell
f :: forall a. (a, a->Int) -> Int
f (x,h) = h x
所以我们可以不用存在量化,至少在上述情况下。
当它不在箭头左侧时,仍然需要存在量化。例如,
g :: exists a. (a, a->Int)
g = (2 :: Int, \x -> x+3)
唉,Haskell 选择不包含这些类型。可能是为了防止已经复杂的类型系统变得过于复杂。
尽管如此,Haskell 得到了存在数据类型,它只需要围绕存在包装/解包一个构造函数。例如,使用 GADT 语法,我们可以这样写:
data Ex where
E :: forall a. (a, a->Int) -> Ex
g :: Ex
g = E (2 :: Int, \x -> x+3)
最后,让我补充一点,existentials 也可以通过 rank-2 类型和 continuation-passing 来模拟:
g :: forall r. (forall a. (a, a->Int) -> r) -> r
g k = k (2 :: Int, \x -> x+3)