[英]What are these explicit “forall”s doing?
这段代码中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允许我在给出>>
a类型时省略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隐含地拥有它们。
好的,考虑id
的类型, a -> a
。 这是什么a
平均值,它从何而来? 定义值时,不能只使用未在任何位置定义的任意变量。 您需要顶级定义,函数参数或where
子句,&c。 通常,如果使用变量, 则必须将其绑定到某处。
类型变量也是如此, forall
是绑定类型变量的一种方式。 任何地方,你看到没有明确的约束(例如,一个类型变量class Foo a where ...
结合a
,它隐含一个绑定的类定义中) forall
。
所以, id
的类型是隐含的forall a. a -> a
forall a. a -> a
。 这是什么意思? 几乎就是这么说的。 我们可以得到一个类型a -> a
为所有可能的类型a
,或者从另一个角度来看,如果你选择的任何特定类型,你可以得到代表“从你所选择的类型函数本身”一类。 后面的措辞听起来有点像定义一个函数,因此你可以认为forall
类似于lambda抽象类型。
GHC在编译期间使用各种中间表示,并且它应用的一个转换是使函数的相似性更直接:隐式forall
是明确的,并且在多态值用于特定类型的任何地方,它首先应用于类型争论 。
我们甚至可以将forall
和lambdas都写成一个表达式。 我会暂时滥用记谱法并替换forall a.
使用/\\a =>
以获得视觉一致性。 在这种风格中,我们可以定义id = /\\a => \\(x::a) -> (x::a)
或类似的东西。 因此,代码中的id True
的表达式最终将转换为id Bool True
; 只是id True
不再有意义。
正如您可以重新排序函数参数一样,您也可以重新排序类型参数,仅受限于类型参数必须在该类型的任何值参数之前出现的(相当明显的)限制。 由于隐式forall
始终是最外层,因此GHC可能会在明确表示时选择所需的任何顺序。 一般情况下,这显然无所谓。
我不确定在这种情况下到底发生了什么,但根据评论我会猜测,在某种意义上,使用显式类型参数的转换和do
notation的贬值是彼此不了解的,因此明确指定类型参数的顺序以确保一致性。 毕竟,如果某些东西盲目地将两个类型的参数应用于表达式,那么该表达式的类型是否为forall a b. ma -> mb -> mb
是很重要的forall a b. ma -> mb -> mb
forall a b. ma -> mb -> mb
或forall b a. ma -> mb -> mb
forall b a. ma -> mb -> mb
!
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.