简体   繁体   English

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

[英]Haskell explicit forall with “missing” type parameter on lhs

I was reading the source code of haxl-Haxl.Core I came upon the following piece of code 我正在阅读haxl-Haxl的源代码.Core我发现了以下代码

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

And realized that I don't fully understand the usage of ExplicitForall / ExistentialQuantification . 并意识到我并不完全理解ExplicitForall / ExistentialQuantification的用法。

In what ways is the snippet above different from 上面的代码片段在哪些方面有所不同

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

And why can I "omit" the type parameter on the lhs of the data declaration. 为什么我可以“省略”数据声明的lhs上的类型参数。

As others have mentioned, the example from the code is an example of an existential quantification, and so is totally different from the final example in the question. 正如其他人所提到的,代码中的示例是存在量化的示例,因此与问题中的最终示例完全不同。

The first thing to note is that nowadays GADT notation is often preferred for this. 首先要注意的是,现在GADT符号通常是首选。 The type in GADT notation is: GADT表示法中的类型是:

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

We can explicitly bind a as follows: 我们可以明确地绑定a如下:

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

This would be isomorphic to the following if we had free existential quantification: 如果我们有免费的存在量化,这将与以下同构:

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

This, combined with a desire not to introduce new keywords, is what led to the old ExistentialQuantification syntax. 这与不引入新关键字的愿望相结合,导致了旧的ExistentialQuantification语法。 The BlockedFetch data constructor has type BlockedFetch数据构造函数具有类型

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

and this is what is trying to be communicated with the syntax: 这就是尝试与语法沟通的内容:

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

From this perspective the difference from having BlockedFetch ra is then the a would occur in the result of the data constructor type. 从这个角度看,与BlockedFetch ra的不同之处在于,数据构造函数类型的结果会出现a Schematically, forall a. F a -> G 示意性地, forall a. F a -> G forall a. F a -> G is logically equivalent to (exists a. F a) -> G , but it is clearly not the case that forall a. F a -> G a 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 is equivalent to (exists a. F a) -> G a as the latter is not even well-scoped. forall a. F a -> G a相当于(exists a. F a) -> G a因为后者甚至没有良好的范围。

Returning to 回到

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

if you don't understand existentials, but you do understand universal quantification, then you can understand what's going on in terms of that. 如果你不了解存在感,但你确实理解了普遍的量化,那么你就可以理解这是怎么回事。 Here we see that someone calling BlockedFetch , ie building a value with the data constructor, is free to choose whichever type they want for a . 在这里,我们看到,有人 BlockedFetch ,即建设一个值与数据的构造,可以自由地选择他们想要哪个类型的a Someone consuming , ie pattern matching on, a value of type BlockedFetch R is essentially writing a function forall a. R a -> ResultVar a -> X 消费 (即模式匹配) BlockedFetch R类型的BlockedFetch R实际上是在写一个函数forall a. R a -> ResultVar a -> X forall a. R a -> ResultVar a -> X and that function must work for any value of a , ie the person calling this function gets to choose a and this function must work with that choice. forall a. R a -> ResultVar a -> X和功能必须努力的任何a ,即调用该函数就可以选择的人a和这个功能必须与选择工作。

The difference is that you can (and in fact this happens a little further in the code) make a list of type [BlockedFetch request] where individual BlockedFetch have different a types (which you could not do with [BlockedFetch request a] - the a here has to be the same for the whole list). 区别在于你可以(实际上这在代码中稍微发生)制作一个类型[BlockedFetch request]的列表,其中各个BlockedFetch具有不同a类型(你不能用[BlockedFetch request a] - - a这里必须是整个列表相同)。 The comment above the snippet of code explains this nicely: 代码片段上方的注释很好地解释了这一点:

-- 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'.

Roughly what happens in Haxl is that you want to have a way of fetching a bunch of values of different types in parallel from some remote store. Haxl中发生的大致情况是,您希望能够从某个远程存储中并行获取不同类型的一组值。 The way you do this is by making a bunch of MVar which will contain the values you plan on getting. 你这样做的方法是制作一堆MVar ,它将包含你计划得到的值。 Then, in your code, you freely use these variables. 然后,在您的代码中,您可以自由地使用这些变量。 However, and MVar blocks until it is "filled". 但是, MVar阻塞,直到它被“填充”。

However, to fill the MVar , you only need to keep a reference to the MVar and a way of filling it - so at the end of the day you don't even need to know what the type is of the stuff the MVar will contain. 但是,为了填充MVar ,你只需要保留对MVar的引用和填充它的方法 - 所以在一天结束时你甚至不需要知道MVar将包含的东西的类型是什么。 That is an existential type - there exists some type a which the BlockedFetch is going to try to fill, but it will vary for different BlockedFetch s. 这是一个存在的类型-存在某种类型的a其中BlockedFetch是要去尝试填补,但它会针对不同而异BlockedFetch秒。

Consider a simpler example: 考虑一个更简单的例子:

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

Read it as 读它为

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

and now it's clear that ShowBox can contain a value of any type as long as this type is an instance of Show . 现在很明显,只要此类型是Show的实例, ShowBox就可以包含任何类型的值。 Eg 例如

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

So you can read 所以你可以阅读

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

as " BlockedFetch contains an ra and ResultVar a for whatever a ". 因为“ BlockedFetch包含一个raResultVar a for for a ”。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM