Haskell显式forall在lhs上有“缺失”类型参数

时间:2016-11-08 07:32:29

标签: haskell

我正在阅读haxl-Haxl.Core的源代码,我发现了以下代码

data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a)

并意识到我并不完全理解ExplicitForall / ExistentialQuantification的用法。

上面的代码段与

有什么不同
data BlockedFetch r a = BlockedFetch (r a) (ResultVar a)

为什么我可以“省略”数据声明的lhs上的类型参数。

3 个答案:

答案 0 :(得分:5)

正如其他人所提到的,代码中的例子是存在量化的一个例子,因此与问题中的最后一个例子完全不同。

首先要注意的是,现在GADT符号通常是首选。 GADT表示法中的类型是:

data BlockedFetch r where
    BlockedFetch :: r a -> ResultVar a -> BlockedFetch r

我们可以按如下方式明确绑定a

data BlockedFetch r where
    BlockedFetch :: forall a. r a -> ResultVar a -> BlockedFetch r

如果我们有免费的存在量化,这将与以下同构:

data BlockedFetch r where
    BlockedFetch :: (exists a. (r a, ResultVar a)) -> BlockedFetch r

这与不引入新关键字的愿望相结合,导致了旧的ExistentialQuantification语法。 BlockedFetch数据构造函数的类型为

BlockedFetch :: forall r a. r a -> ResultVar a -> BlockedFetch r

这就是尝试与语法沟通的内容:

data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a)

从这个角度看,与BlockedFetch r a的区别在于a将出现在数据构造函数类型的结果中。原则上,forall a. F a -> G在逻辑上等同于(exists a. F a) -> G,但显然不是forall a. F a -> G a等同于(exists a. F a) -> G a的情况,因为后者甚至没有完善范围。

返回

BlockedFetch :: forall r a. r a -> ResultVar a -> BlockedFetch r

如果你不了解存在感,但你确实理解普遍量化,那么你就可以理解这方面的进展情况。在这里,我们看到有人调用 BlockedFetch,即使用数据构造函数构建值,可以自由选择他们想要a的任何类型。某人消费,即模式匹配,类型BlockedFetch R的值实际上是编写函数forall a. R a -> ResultVar a -> X,该函数必须适用于任何a,即调用此函数的人可以选择a,此函数必须适用于该选项。

答案 1 :(得分:2)

不同之处在于你可以(实际上这在代码中稍微发生了一点)制作了[BlockedFetch request]类型的列表,其中个别BlockedFetch具有不同的a类型(你与[BlockedFetch request a]无关 - 此处的a必须与整个列表相同。代码片段上方的注释很好地解释了这一点:

-- We often want to collect together multiple requests, but they return
-- different types, and the type system wouldn't let us put them
-- together in a list because all the elements of the list must have the
-- same type. So we wrap up these types inside the 'BlockedFetch' type,
-- so that they all look the same and we can put them in a list.
--
-- When we unpack the 'BlockedFetch' and get the request and the 'ResultVar'
-- out, the type system knows that the result type of the request
-- matches the type parameter of the 'ResultVar', so it will let us take the
-- result of the request and store it in the 'ResultVar'.

Haxl中发生的大致情况是,您希望能够从某个远程存储中并行获取一堆不同类型的值。你这样做的方法是制作一堆MVar,其中包含你计划得到的值。然后,在您的代码中,您可以自由地使用这些变量。但是,MVar阻止,直到#34;填充"。

但是,要填写MVar,您只需要保留对MVar的引用以及填写它的方法 - 所以在一天结束时您甚至不需要要知道MVar将包含的内容的类型。这是一种存在类型 - a会尝试填充某些类型BlockedFetch,但它会因不同的BlockedFetch而异。

答案 2 :(得分:1)

考虑一个更简单的例子:

data ShowBox = forall a. Show a => ShowBox a

将其读作

data ShowBox = whatever a. Show a => ShowBox a

现在很明显ShowBox可以包含任何类型的值,只要此类型是Show的实例即可。 E.g。

ex :: [ShowBox]
ex = [ShowBox 'a', ShowBox (), ShowBox [1,2,3]]

所以你可以阅读

data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a)

BlockedFetch包含r aResultVar a,适用于a”。