Javascript 为什么承诺是单子?
我一直在学习函数式编程,遇到过单子、函子和应用程序 根据我的理解,以下定义适用: 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]),一个通常具有签名的函数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=>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)
是身份识别功能。我们可以简单地在JS中实现它,比如varid
id=x=>x
中的(p.q)
与数学中的合成运算一样。它本质上是JS中的vardot=p=>q=>x=>p(q(x))
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)