Jac*_*par 22 javascript monads functional-programming functor es6-promise
我一直在学习函数式编程,并且遇到了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.我错过了什么?
Dmi*_*sev 29
它不是一个仿函数,因为 违反了构图保存法(将函数的组合发送到图像的组合):
promise.then(x => g(f(x)))
Run Code Online (Sandbox Code Playgroud)
实际上,这意味着重构永远不会安全
promise.then(f).then(g)
Run Code Online (Sandbox Code Playgroud)
至
promise
.then(x => f(x))
.then(y => g(y))
Run Code Online (Sandbox Code Playgroud)
就像它本来一样,是Promise一个仿函数.
函子违法行为的证明.这是一个反例:
promise
.then(x => g(f(x))
Run Code Online (Sandbox Code Playgroud)
以下是Codepen上的示例:https://codepen.io/dmitriz/pen/QrMawp ? edit = 0011
由于组合h是身份功能,因此promise.then(h)只需采用promise已经用身份完成的状态a => a.
另一方面,f返回所谓的那么:
1.2."thenable"是定义then方法的对象或函数.
为了维护仿函法,.then必须简单地将结果包含在承诺中f(x).相反,当函数内部返回"thenable" 时,Promise Spec需要不同的行为.then.根据2.3.3.3,密钥id = a => a下存储的身份函数then称为
//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)
})
其中resolvePromise和rejectPromise是由promise解决程序提供的两个回调函数.但是,为了得到解决或拒绝,必须调用其中一个回调函数,这些函数永远不会发生!因此,由此产生的承诺仍处于待决状态.
在此示例中,
promise.then(x => g(f(x)))
使用标识函数实现a => a,而
promise.then(f).then(g)
永远保持在挂起状态.因此,这两个承诺并不等同,因此违反了仿函法.
因为即使是Pointed Functor Spec 的自然变换定律,也就是属于Applicative(同态定律)的一部分,也被违反了:
id(resolvePromise, rejectPromise)
Run Code Online (Sandbox Code Playgroud)
证明.这是一个反例:
Promise.resolve(g(x)) is NOT equivalent to Promise.resolve(x).then(g)
Run Code Online (Sandbox Code Playgroud)
Codepen上的这个例子:https://codepen.io/dmitriz/pen/wjqyjY ? edit = 0011
在这个例子中,一个承诺得以实现,而另一个承诺未决,因此这两个在任何意义上都不相同,违反了法律.
小智 7
Promise是(很像)一个 monad,因为then它过载了。
当我们使用 Promise.then(func) 时,我们向 Promise(即 C[A])传递一个通常具有签名 A => B 的函数并返回另一个 Promise(即 C[B])。所以我的想法是 Promise 只是一个 Functor 而不是 Monad,因为 func 返回 B 而不是 C[B]。
这是真的then(Promise<A>, Func<A, B>) : Promise<B>(如果你原谅我的 javascript 类型的伪代码,我会将函数描述为好像this是第一个参数)
无极API用品另一个签名then虽然,then(Promise<A>, Func<A, Promise<B>>) : Promise<B>。这个版本显然符合 monadic bind ( >>=)的签名。自己试试看,确实有效。
然而,为 monad 拟合签名并不意味着 Promise是一个 monad。它还需要满足单子的代数定律。
monad 必须满足的定律是结合律
(m >>= f) >>= g ? m >>= ( \x -> (f x >>= g) )
Run Code Online (Sandbox Code Playgroud)
以及左右身份的法则
(return v) >>= f ? f v
m >>= return ? m
Run Code Online (Sandbox Code Playgroud)
在 JavaScript 中:
(m >>= f) >>= g ? m >>= ( \x -> (f x >>= g) )
Run Code Online (Sandbox Code Playgroud)
我想任何熟悉 Promise 的人都可以看到所有这些都应该是真实的,但您可以随意尝试一下。
因为 Promise 是一个 monad,我们也可以从中派生ap并得到一个应用程序,给我们一些非常好的语法,但有点不明智:
(return v) >>= f ? f v
m >>= return ? m
Run Code Online (Sandbox Code Playgroud)
小智 5
Promise 将包含 then 属性(即函数)的对象视为特殊情况。因此,他们违反了左同一律,如下所示:
//Law of left identity is violated
// g(v) vs Promise.resolve(v).then(g)
// identity function saved under `then` prop
const v = ({then: x=>x({then: 1})})
// `g` returns the `then` prop from object wrapped in a promise
const g = (obj => Promise.resolve(obj.then))
g(v).then(res =>
console.log("g(v) returns", res))
// "g(v) returns" x => x({ then: 1 })
Promise.resolve(v).then(g)
.then(res =>
console.log("Promise.resolve(v).then(g) returns", res))
// "Promise.resolve(v).then(g) returns" 1
Run Code Online (Sandbox Code Playgroud)
发生这种情况是因为resolve将then属性下的函数视为回调,将then链的延续作为参数传递,而不是创建包含它的promise。这样,它就不像单元一样发挥作用,并导致违反单子定律。
但是,对于不包含 then 属性的值,它应该充当 monad。
Red*_*edu -5
根据我的说法,Promise 是函子、应用函子和单子,因为它们遵守函子和单子定律。
好吧,让我们研究一下函子案例。为了使 Promise 成为 Functor 的实例,我们必须为 Promise定义一个fmap函数并通过 Functor 法则。什么是函子定律?(a -> b) - f a -> f bfmap
fmap id = id
fmap (p . q) = (fmap p) . (fmap q)
Run Code Online (Sandbox Code Playgroud)
id是恒等函数。我们可以像var一样简单地在JS中实现它id = x => x.。(p . q)它本质上是var dot = p => q => x => p(q(x))在 JS 中。JS 中的问题在于,对象(包括函数)都是引用类型,这意味着与 Haskell 不同,每次部分应用函数时,都会得到一个不同的函数做同样的事情。因此,仅以下法律中的权益检查将会失败,但如果您检查结果值,它们就会通过。
fmap id = id
fmap (p . q) = (fmap p) . (fmap q)
Run Code Online (Sandbox Code Playgroud)
所以,是的,Promise 是 Functor,如果你检查Monad 法则,你可以很容易地看出它们也是 Monad。