这些明确的“forall”在做什么?

时间:2012-09-20 19:49:26

标签: haskell higher-rank-types 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

(没有错误)。

1 个答案:

答案 0 :(得分:11)

  

我的背景:我不太了解forall或Haskell隐含地拥有它们。

好的,请考虑ida -> a的类型。 a是什么意思,它来自哪里?定义值时,不能只使用未在任何位置定义的任意变量。您需要顶级定义,函数参数或where子句,& c。通常,如果您在某处使用变量it must be bound

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

因此,id的类型隐含forall a. a -> a。这是什么意思?几乎就是这么说的。我们可以为所有可能的类型a -> a获取类型a ,或者从另一个角度获取,如果您选择任何特定类型,您可以获得表示“所选类型的函数”的类型对自己“。后面的措辞听起来有点像定义一个函数,因此你可以认为forall类似于类型的lambda抽象。

GHC在编译期间使用各种中间表示,并且它应用的一个转换是使函数的相似性更直接:隐式forall s是显式的,并且任何地方的多态值都用于特定类型,它首先应用于类型参数

我们甚至可以将forall和lambdas都写成一个表达式。我会暂时滥用注释,并将forall a.替换为/\a =>以保持视觉一致性。在这种风格中,我们可以定义id = /\a => \(x::a) -> (x::a)或类似的东西。因此,代码中的id True这样的表达式最终会转换为类似id Bool True的内容;只有id True才会有意义。

正如您可以重新排序函数参数一样,您也可以重新排序类型参数,仅受限于类型参数必须在该类型的任何值参数之前出现的(相当明显的)限制。由于隐式forall始终是最外层,因此GHC可能会在明确时选择任何所需的顺序。在正常情况下,这显然无所谓。

我不确定完全在这种情况下发生了什么,但根据评论我会猜测转换为使用显式类型参数和des do表示法是,在某种意义上,彼此不了解,因此明确指定类型参数的顺序以确保一致性。毕竟,如果某些东西盲目地将两个类型的参数应用于表达式,那么该表达式的类型是forall a b. m a -> m b -> m b还是forall b a. m a -> m b -> m b是非常重要的!