这些明确的"forall"在做什么?



此代码中forall的用途是什么?

class  Monad m  where
(>>=)       :: forall a b. m a -> (a -> m b) -> m b
(>>)        :: forall a b. m a -> m b -> m b
-- Explicit for-alls so that we know what order to
-- give type arguments when desugaring

(省略了一些代码)。这是Monads的代码。


我的背景:我不太了解forall,也不知道Haskell什么时候隐含了它们。

此外,它可能并不重要,但GHCi允许我在给>>一个类型时省略forall

Prelude> :t (>>) :: Monad m => m a -> m b -> m b
(>>) :: Monad m => m a -> m b -> m b
:: (Monad m) => m a -> m b -> m b

(没有错误)。

我的背景:我真的不了解forall,也不了解Haskell何时隐式地拥有它们。

好的,考虑ida -> a的类型。a是什么意思?它来自哪里?当你定义一个值时,你不能只使用没有在任何地方定义的任意变量。您需要一个顶级定义、函数参数或where子句,&c.一般来说,如果你使用一个变量,它必须绑定在某个地方。

类型变量也是如此,forall就是绑定类型变量的一种方法。在任何您看到的类型变量没有显式绑定的地方(例如,class Foo a where ...在类定义中绑定a),它都是由forall隐式绑定的。

因此,id的类型隐含地为forall a. a -> a。这是什么意思?几乎和上面说的一样。我们可以为所有可能的类型a获得类型a -> a,或者从另一个角度来看,如果您选择任何特定类型,您可以获得表示"从您选择的类型到其自身的函数"的类型。后一种措辞听起来应该有点像定义函数,因此您可以将forall视为类似于类型的lambda抽象。

GHC在编译过程中使用各种中间表示,它应用的转换之一是使与函数的相似性更直接:隐式foralls被显式化,在任何为特定类型使用多态值的地方,它首先被应用于类型参数。

我们甚至可以将foralls和lambdas写成一个表达式。我将暂时滥用表示法,并将forall a.替换为/a =>以获得视觉一致性。在这种风格中,我们可以定义id = /a => (x::a) -> (x::a)或类似的东西。因此,代码中类似id True的表达式最终会被翻译成类似id Bool True的表达式;仅仅CCD_ 25将不再有意义。

正如您可以重新排序函数参数一样,您也可以重新排序类型参数,只受类型参数必须在该类型的任何值参数之前的限制(相当明显)。由于隐式forall总是最外层,GHC在使其显式时可能会选择它想要的任何顺序。在正常情况下,这显然无关紧要。

我不确定在这种情况下到底发生了什么,但根据评论,我猜在某种意义上,向使用显式类型参数的转换和对do表示法的淡化是相互不知道的,因此显式指定了类型参数的顺序以确保一致性。毕竟,如果有东西盲目地将两个类型参数应用于一个表达式,那么该表达式的类型是forall a b. m a -> m b -> m b还是forall b a. m a -> m b -> m b就非常重要了!

相关内容

  • 没有找到相关文章

最新更新