Javascript 为什么承诺是单子?

Javascript 为什么承诺是单子?,javascript,functional-programming,monads,es6-promise,functor,Javascript,Functional Programming,Monads,Es6 Promise,Functor,我一直在学习函数式编程,遇到过单子、函子和应用程序 根据我的理解,以下定义适用: a) (a=>B=>C[a]=>C[B]|函子 b) (A=>C[b])=>C[A]=>C[b]|单子 c) (c[A=>B])=>c[A]=>c[B]|适用 (参考资料:) 此外,我知道单子是函子的特例。与中一样,它应用一个函数,该函数将返回包装值到包装值并返回包装值 当我们使用Promise.then(func)时,我们传递的是Promise(即C[A]),一个通常具有签名的函数A=>B,并返回另一个Promi

我一直在学习函数式编程,遇到过单子、函子和应用程序

根据我的理解,以下定义适用:

a) (a=>B=>C[a]=>C[B]|函子

b) (A=>C[b])=>C[A]=>C[b]|单子

c) (c[A=>B])=>c[A]=>c[B]|适用

(参考资料:)

此外,我知道单子是函子的特例。与中一样,它应用一个函数,该函数将返回包装值到包装值并返回包装值

当我们使用Promise.then(func)时,我们传递的是Promise(即C[A]),一个通常具有签名的函数
A=>B
,并返回另一个Promise(即C[B])。所以我的想法是一个允诺只能是一个函子而不是一个单子,因为
func
返回B而不是C[B]


然而,通过谷歌搜索,我发现承诺不仅是一个函子,还是一个单子。我想知道为什么
func
不返回包装值C[B]而只返回B。我缺少什么?

根据我的说法,承诺是函子、应用函子和单子,因为它们遵守函子和单子定律

好,让我们来研究函子的情况。为了使承诺成为函子的实例,我们必须为承诺定义
fmap
函数
(a->b)-fa->fb
,并且
fmap
应通过函子定律。什么是函子定律

fmap id      = id
fmap (p . q) = (fmap p) . (fmap q)
  • id
    是身份识别功能。我们可以简单地在JS中实现它,比如var
    id=x=>x
  • (p.q)
    中的
    与数学中的合成运算一样。它本质上是JS中的
    vardot=p=>q=>x=>p(q(x))
JS中的问题是,对象(包括函数)都是引用类型,这意味着与Haskell不同,每次部分应用函数时,都会有不同的函数执行相同的操作。因此,以下定律中的权益检查将失败,但如果检查结果值,它们将通过

var id=x=>x,
点=f=>g=>x=>f(g(x)),
fmap=f=>p=>p。然后(v=>f(v)),
pr1=承诺。解决(1);
fmap(id)(pr1)==id(pr1);//错误,因为对象是可变的
然后(v=>console.log(v));
然后(v=>console.log(v));
fmap(点(x=>x*2)(y=>y+5))(pr1);
点(fmap(x=>x*2))(fmap(y=>y+5))(pr1)
Promise
是单子,因为
然后
被重载

当我们使用Promise.then(func)时,我们传递的是Promise(即C[A]),一个通常签名为A=>B的函数,并返回另一个Promise(即C[B])。所以我的想法是,允诺只能是一个函子,而不是一个单子,因为func返回B而不是C[B]

这对于
then(Promise,Func)是正确的:Promise
(如果您不介意我的伪代码用于javascript类型,我将描述函数,就像
this
是第一个参数一样)

Promise API为
then
提供了另一个签名,
then(Promise,Func):Promise
。此版本显然适合一元绑定的签名(
>=
)。你自己试试看,效果不错

然而,为monad添加签名并不意味着Promise就是monad。它还需要满足单子的代数定律

单子必须满足的定律是结合定律

(m >>= f) >>= g ≡ m >>= ( \x -> (f x >>= g) )
以及左右同一性的法则

(return v) >>= f ≡ f v
m >>= return ≡ m
在JavaScript中:

功能组件等效(px,py){
Promise.all([px,py])。然后([x,y])=>console.log(x==y));
}
var\u return=x=>Promise.resolve(x)
Promise.prototype.bind=Promise.prototype.then
var p=_收益(“foo”)
变量f=x=>\u返回(“条形”)
var g=y=>_返回(“baz”)
资产等价(
p、 绑定(f)。绑定(g),
p、 绑定(x=>f(x).bind(g))
);
资产等价(
_返回(“foo”)。绑定(f),
f(“foo”)
);
资产等价(
p、 绑定(x=>_返回(x)),
P
);UDATE。
看到这个新图书馆了吗
函子与单元算子的证明
用于基于普通回调的函数
不存在不可移动的问题
如下所述:


JS Promise既不是函子,也不是应用程序,也不是单子 它不是函子,因为 (将函数的合成发送到其图像的合成) 违反了:

promise.then(x => g(f(x))) 
Promise.resolve(g(x)) is NOT equivalent to Promise.resolve(x).then(g)
不等于

promise.then(f).then(g)
这实际上意味着什么, 重构永远都不安全

promise
  .then(x => f(x))
  .then(y => g(y))

如果
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) }) // 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) }) // => ??? 其中,
resolvePromise
rejectPromise
是promise解析过程提供的两个回调函数。但是,为了被解析或拒绝,必须调用其中一个回调函数,这永远不会发生!因此,由此产生的承诺仍处于未决状态

结论 在这个例子中,
promise.then(x=>g(f(x)))
由标识函数
a=>a
实现, 鉴于
promise.然后(f).然后(g)
永远处于未决状态。 因此,这两个承诺并不等同 因此违反了函子定律


承诺既不是承诺,也不是承诺 因为甚至违反了规范中的自然变换法则,即存在的一部分(同态法则):

promise.then(x => g(f(x))) 
Promise.resolve(g(x)) is NOT equivalent to Promise.resolve(x).then(g)
证明。以下是一个反例:

//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) }) // 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) }) // => ??? //保存在'then'属性下的标识函数 常数v=({then:a=>a}) //`g`返回`then`prop from object 常数g=obj=>obj.then //`g(v)`是恒等式函数 承诺。解决(g(v))。然后(res=>{ log(“resolve(g(v))返回:”,res) }) //=>“解析(g(v))返回:“a=>a //“v”被包装成永远等待的承诺 //因为它从不调用任何回调 承诺。解决(v)。然后(g)。然后(res=>{ log(“解析(v)。然后(g)返回:”,res)