编程语言
首页 > 编程语言> > javascript – 为什么Promises Monads?

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