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)的约束?
基本上,当你不使用时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).定义是相同的,它的功能相同,但读者现在可以清楚地看到类型变量都是在最顶层定义的.
您编写的每个函数都隐式地通过其类型变量进行量化:
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.