了解Monad'>> ='函数中的所有内容?

在这个答案之后,我在我的程序中实现了一个通用升降功能:

liftTupe :: (x -> c x) -> (a, b) -> (c a, c b) --This will error
liftTuple :: (forall x. x -> c x) -> (a, b) -> (c a, c b)

我明白,在这种情况下, forall使x成为任何类型( []Maybe等)。

我现在正在研究>>=在Monads中的定义:

class Applicative m => Monad m where
   (>>=) :: forall a b. m a -> (a -> m b) -> m b

我无法理解这样的角色forall在函数定义? 与liftTuple不同,它不是绑定到特定函数( x -> cx )?


基本上,当你不使用forall ,所有类型的函数定义,这意味着当函数被调用它们都推断全球。 随着forall可以放弃,对于取函数x ,直到它被称为本身。

所以在第一个函数中你需要一个函数,它需要x并且给出cx ,然后你有一个带有ab的元组,并且你期望一个带有cacb的元组。 既然你已经说过第一个函数接受x ,你可以使xa相同,但它不会是b因为x在整个声明中定义了一次。 所以你不能让这个函数同时接受ab

但是,在第二种情况下, x范围仅限于函数x 。 我们基本上是说有一个函数需要一些东西,并用这个东西来做c ,它可以是任何类型。 这使我们能够首先向其提供a ,然后b ,并且它将起作用。 x现在并不一定是单独的东西。

你在Monad定义中看到的是“ExplicitForAll”语言扩展。 Haskell Prime对此扩展有一个描述

ExplicitForAll允许使用关键字'forall'来显式声明一个类型在其自由类型变量中是多态的。 它不允许写入任何不能写入的类型; 它只允许程序员明确说明(当前隐含的)量化。

这种语言扩展纯粹是可视化的,允许你明确地写出你以前不能的变量。 你可以简单地省略forall a b. 来自Monad声明,并且该程序将在功能上保持完全相同。

说,用这个扩展名,你可以将liftTupe改写为forall ab x. (x -> cx) -> (a, b) -> (ca, cb) forall ab x. (x -> cx) -> (a, b) -> (ca, cb) 。 定义相同,功能相同,但读者现在可以清楚地看到,类型变量都定义在最上层。


你写的每一个函数都是通过它的类型变量被隐含地普遍量化的:

id :: a -> a           -- this is actually universally quantified over a
id :: forall a. a -> a
id x = x

您可以使用ExplicitForall语言附注实际打开此行为。

该属性非常有用,因为它限制了您编写仅适用于某些类型的代码。 想一想id函数可以做些什么:它可以永远返回它的参数或循环。 这是它可以做的唯一两件事情,你可以根据它的类型签名来判断。

强制多态函数的所有实例的行为方式相同,不论类型参数如何,称为parametricity,在本博文中由Bartosz Milewski解释。 TL; DR是:使用参数性,我们可以保证在程序结构中的一些重新排序不会影响它的行为。 对于这个数学上更严格的处理,请参阅免费的定理! 由菲利普Wadler。


在Haskell的类型系统中的所有类型的变量由量化forall 。 但是,GHC可以在许多情况下推断量化,因此您无需在源代码中编写它们。

例如类型liftTupleforall明确的是

liftTuple :: forall c a b. (forall x. x -> c x) -> (a, b) -> (c a, c b)

对于>>=情况是一样的。

链接地址: http://www.djcxy.com/p/77373.html

上一篇: Understanding forall in Monad '>>=' function?

下一篇: Monad Transformers lift