在Monad'>> ='函数中理解forall?

Bab*_*ham 11 monads haskell forall

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

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)
Run Code Online (Sandbox Code Playgroud)

我明白的是,在此背景下,forall正在使x是任何类型的([],Maybe等.).

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

class Applicative m => Monad m where
   (>>=) :: forall a b. m a -> (a -> m b) -> m b
Run Code Online (Sandbox Code Playgroud)

我无法理解这forall在函数定义中的作用?liftTuple与之不同,它不受特定函数(x -> c x)的约束?

Mal*_*olm 6

基本上,当你不使用时forall,所有类型在函数定义中都是全局的,这意味着它们都是在调用函数时推导出来的.随着forall你可以放弃功能,x直到它被称为自己.

所以在第一个你有一个函数,它接受x和给予c x,那么你有一个元组a,并b期待与您有一个元组c a和c b.因为你已经说过第一个函数接受了x,你可以使它x变得相同a,但是它不会b因为x整个声明被定义一次.所以你不能让函数同时接受a和b.

但是,在第二种情况下,x范围仅限于功能x.我们基本上说有一个功能可以采取某些东西并c使用这个东西,它可以是任何类型.这使我们能够首先a为它提供食物,然后b它就可以了.x现在不必是外面的单数.

您在Monad定义中看到的是"ExplicitForAll"语言扩展.有关此扩展的Haskell Prime的说明

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

这种语言扩展是纯粹的可视化,允许您明确地写出您以前无法读取的变量.你可以简单地忽略forall a b.从Monad申报,并计划将在功能上保持完全不变.

说,通过此扩展,您可以重写liftTupeas forall a b x. (x -> c x) -> (a, b) -> (c a, c b).定义是相同的,它的功能相同,但读者现在可以清楚地看到类型变量都是在最顶层定义的.


Thr*_*eFx 5

您编写的每个函数都隐式地通过其类型变量进行量化:

id :: a -> a           -- this is actually universally quantified over a
id :: forall a. a -> a
id x = x
Run Code Online (Sandbox Code Playgroud)

您实际上可以使用ExplicitForall语言编译指示启用此行为.

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

强制多态函数的所有实例的行为方式相同,不论类型参数被称为parametricity在解释这个由巴尔托什卢斯基博客文章.TL; DR是:使用参数,我们可以保证程序结构中的某些重新排序不会影响它的行为.对于数学上更严格的处理方法,请免费参阅Theoreorems!作者:Philip Wadler.