[英]Haskell explicit forall with “missing” type parameter on lhs
正如其他人所提到的,代码中的示例是存在量化的示例,因此与问题中的最终示例完全不同。
首先要注意的是,现在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 ra
的不同之处在于,数据构造函数类型的结果会出现a
。 示意性地, forall a. F a -> G
forall a. F a -> G
在逻辑上等同于(exists a. F a) -> G
,但显然不是forall a. F a -> G a
的情况forall a. F a -> G a
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
类型的BlockedFetch R
实际上是在写一个函数forall a. R a -> ResultVar a -> X
forall a. R a -> ResultVar a -> X
和功能必须努力的任何值a
,即调用该函数就可以选择的人a
和这个功能必须与选择工作。
区别在于你可以(实际上这在代码中稍微发生)制作一个类型[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
阻塞,直到它被“填充”。
但是,为了填充MVar
,你只需要保留对MVar
的引用和填充它的方法 - 所以在一天结束时你甚至不需要知道MVar
将包含的东西的类型是什么。 这是一个存在的类型-存在某种类型的a
其中BlockedFetch
是要去尝试填补,但它会针对不同而异BlockedFetch
秒。
考虑一个更简单的例子:
data ShowBox = forall a. Show a => ShowBox a
读它为
data ShowBox = whatever a. Show a => ShowBox a
现在很明显,只要此类型是Show
的实例, ShowBox
就可以包含任何类型的值。 例如
ex :: [ShowBox]
ex = [ShowBox 'a', ShowBox (), ShowBox [1,2,3]]
所以你可以阅读
data BlockedFetch r = forall a. BlockedFetch (r a) (ResultVar a)
因为“ BlockedFetch
包含一个ra
和ResultVar a
for for a
”。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.