javascript – 为什么Promises Monads?
作者:互联网
我一直在学习函数式编程,并且遇到了Monads,Functors和Applicatives.
根据我的理解,以下定义适用:
a)(A => B)=> C [A] => C [B] |函子
b)(A => C [B])=> C [A] => C [B] |单子
c)(C [A => B])=> C [A] => C [B] |合用的
(参考:https://thedet.wordpress.com/2012/04/28/functors-monads-applicatives-can-be-so-simple/)
此外,我了解Monad是Functor的一个特例.在中,它应用一个函数,该函数将包装值返回到包装值并返回包装值.
当我们使用Promise.then(func)时,我们传递Promise(即C [A])一个通常具有签名A =>的函数. B并返回另一个Promise(即C [B]).所以我的想法是,Promise只是一个Functor而不是Monad,因为func返回B而不是C [B].
然而,谷歌搜索我发现Promise不仅是一个Functor,也是一个Monad.我想知道为什么,因为func没有返回包裹值C [B]而只是B.我错过了什么?
解决方法:
UDATE.
看到这个新图书馆
证明函子和monad运算符
用于基于回调的普通函数
那些没有问题的问题
如下所述:
https://github.com/dmitriz/cpsfy
JS Promise既不是Functor也不是Applicative,也不是Monad
它不是一个算符,因为
composition preservation law
(将函数组合发送到其图像的合成)
被违反:
promise.then(x => g(f(x)))
不等同于
promise.then(f).then(g)
这实际上意味着什么,
重构永远不会安全
promise
.then(x => f(x))
.then(y => g(y))
至
promise
.then(x => g(f(x))
就像它本来一样,Promise是一个仿函数.
函子违法行为的证明.这是一个反例:
//Functor composition preservation law: // promise.then(f).then(g) vs promise.then(x => g(f(x))) // f takes function `x` // and saves it in object under `then` prop: const f = x => ({then: x}) // g returns the `then` prop from object const g = obj => obj.then // h = compose(g, f) is the identity const h = x => g(f(x)) // fulfill promise with the identity function const promise = Promise.resolve(a => a) // this promise is fulfilled with the identity function promise.then(h) .then(res => { console.log("then(h) returns: ", res) }) // => "then(h) returns: " a => a // but this promise is never fulfilled promise.then(f) .then(g) .then(res => { console.log("then(f).then(g) returns: ", res) }) // => ??? // because this one isn't: promise.then(f) .then(res => { console.log("then(f) returns: ", res) })
这是Codepen上的这个例子:
https://codepen.io/dmitriz/pen/QrMawp?editors=0011
说明
由于组合h是身份函数,所以promise.then(h)简单地采用了承诺的状态,其已经用身份a =>来实现.一个.
另一方面,f返回所谓的thenable:
1.2. “thenable” is an object or function that defines a then method.
为了维护仿函数法则,然后必须简单地将结果f(x)包含在承诺中.相反,当.then中的函数返回“thenable”时,Promise Spec需要不同的行为.根据2.3.3.3,身份功能id = a =>存储在then键下的一个被称为
id(resolvePromise, rejectPromise)
其中resolvePromise和rejectPromise是promise解析过程提供的两个回调函数.但是,为了得到解决或拒绝,必须调用其中一个回调函数,这些函数永远不会发生!因此,由此产生的承诺仍处于待决状态.
结论
在这个例子中,
promise.then(x => g(f(x)))
用身份函数a =>来实现一个,
而
promise.then(F).然后(G)
永远处于待定状态.
因此,这两个承诺并不相同
因此违反了仿函法.
承诺既不是Monad也不是Applicative
因为即使是Pointed Functor规范中的自然变换定律,即Applicative(同态定律)的一部分,也被违反:
Promise.resolve(g(x)) is NOT equivalent to Promise.resolve(x).then(g)
证明.这是一个反例:
// identity function saved under `then` prop const v = ({then: a => a}) // `g` returns `then` prop from object const g = obj => obj.then // `g(v)` is the identity function Promise.resolve(g(v)).then(res => { console.log("resolve(g(v)) returns: ", res) }) // => "resolve(g(v)) returns: " a => a // `v` is unwrapped into promise that remains pending forever // as it never calls any of the callbacks Promise.resolve(v).then(g).then(res => { console.log("resolve(v).then(g) returns: ", res) }) // => ???
Codepen上的这个例子:https://codepen.io/dmitriz/pen/wjqyjY?editors=0011
结论
在这个例子中,一个承诺得以实现,而另一个承诺未决,因此这两个在任何意义上都不相同,违反了法律.
UPDATE.
究竟“成为一个Functor”是什么意思?
Promise作为Functor / Applicative / Monad之间似乎存在混淆,以及通过改变方法或添加新方法来实现这一点的方式.但是,Functor必须具有已经提供的map方法(不一定以此名称),并且作为Functor显然取决于此方法的选择.只要法律得到满足,方法的实际名称就不起任何作用.
对于Promises,.then是最自然的选择,它不符合下面解释的Functor定律.据我所知,其他Promise方法都没有以任何可能的方式使它成为Functor.
更改或添加方法
是否可以定义符合法律的其他方法是另一回事.我所知道的这个方向的唯一实现是由creed library提供的.
但是需要付出相当大的代价:不仅需要定义全新的map方法,而且还需要更改promise对象本身:信条承诺可以保持“有效”作为价值,而原生JS承诺可以’吨.这种变化是实质性的,并且必须避免违反实施例中的法律,如下所述.特别是,我没有任何方法将Promise变成Functor(或Monad)而没有这些根本性的变化.
标签:javascript,monads,functional-programming,es6-promise,functor 来源: https://codeday.me/bug/20190922/1813294.html