我正在阅读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上的类型参数。
答案 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 a
和ResultVar a
,适用于a
”。