我正在努力理解 JavaScript 中的单元函数。特别是因为让我“得到”monad(或者至少我认为)的是 Promise 对象,以及 then
总是返回一个新的 Promise,无论你传递给 then 什么函数
,据我所知,它等同于 haskell 中的 bind
或 >>=
。这对我来说完全有意义,因为它可以确保您的所有功能都在“monad 宇宙”中执行,可以这么说。
让我感到困惑的是道格拉斯·克罗克福德 (Douglas Crockford) 的“单子(monad)和性腺”演讲。在他的实现中,bind
直接返回转换函数的结果,而不检查结果本身是否是 monad。这与 Promises 的 then
方法冲突,因为 then
总是返回一个新的 Promise。
一个想法是提升方法。他的实现确实确保“提升”将始终返回一个 monad,并且可能 then
被提升到 Promise。然而,这意味着 then !== bind
,并且 Promise 在某处有一个内部绑定(bind)。
我的直觉是,至少应该在绑定(bind)函数中进行某种类型检查,检查转换的结果,并允许生成的 monad 通过,但会拦截非 monad 并将它们传递给 unit再次,就像“提升”一样。
*编辑
另外,我的印象是 then
等同于 bind, flatMap, >>=
因为它有能力打开其他 monad,包括不同的和它是自己的类型。在查看 JavaScript 中的一些类别理论引用资料时,flatMap
用于映射一组嵌套数组,然后将它们按一个维度展平。这符合 then
等待您提供的其他 promise 的方式。但似乎与上面提到的原始实现不匹配。我感到迷茫。
任何有更多 FP 经验的人都可以阐明我遗漏了什么,还是我太过分了,需要从头开始?
一些代码示例...
// Crockford's 'bind'
monad.bind = function(transform) {
// value was passed in through the unit constructor
return transform(value);
}
我的问题所在
// Set the 'isMonad' prop to be true, for all
// monads made with the MONAD macroid
monad.isMonad = true;
// shouldn't this ALWAYS return a monad?
monad.bind = function(transform) {
var res = transform(value);
return ( res && res.isMonad ) ? res : unit(res);
}
注意我知道我没有完整使用他的最终版本,我只是特别关注绑定(bind)方法。
完整的实现可以在
找到https://github.com/douglascrockford/monad/blob/master/monad.js
更新
经过更多研究,>>=
不需要返回 Monad 实例。 Bergi 的评论阐明了 Promise.prototype.then
是如何重载的,并根据您使用的解析方式充当不同的函数。
此外,当我退后一步并查看 Monad 与常规仿函数的不同之处时,很多事情开始变得清晰起来。细节仍然有点模糊,但我想我明白了大局。
一些有助于消除阴霾的好引用,
强烈推荐使用人类语言进行高级概述
http://adit.io/posts/2013-04-17-functors,_applicatives,_and_monads_in_pictures.html
不要让这些照片骗了你,这对我来说就像金子一样。不是在 JavaScript 中,但对于整体概念仍然非常有用。
另外,这个关于 JavaScript 范畴论的 YouTube 系列
https://www.youtube.com/watch?v=-FkgOHvNAU8&list=PLwuUlC2HlHGe7vmItFmrdBLn6p0AS8ALX&index=1
这个名为“Fun Fun Function”的 YouTube 系列非常精彩,主持人是我在网上找到的最好的老师之一。该视频是关于单子(monad)的,由 MrE
推荐。
强烈推荐!。
https://www.youtube.com/watch?v=9QveBbn7t_c&app=desktop
这两个引用文献特别为我创造了奇迹。希望对其他人也有帮助。
最佳答案
我不太明白你的问题是什么,但我假设是这样的:
what is the correct definition of a Monad and it's two methods in terms of JS?
在 Haskell 术语中(取自 https://en.wikibooks.org/wiki/Haskell/Understanding_monads ),它很简单:
return :: a -> m a
(>>=) :: m a -> (a -> m b) -> m b
(>>) :: m a -> m b -> m b
对于 JavaScript 术语,不用再找了,这里有简短的答案 https://github.com/fantasyland/fantasy-land#monad 以及其他相关的 FP 定义。
关于方法的几句话:
有一件事是
unit
(Haskell 中的return
)必须产生一个 monad(不完全是 monad,但为了论证) ...),因为它就像一个将值放入容器中的构造函数。Array.of()
是一个示例,jQuery()
是另一个示例,当然还有new Promise()
。在 Fantasy Land 规范中,这是
of()
函数/方法。第二个很重要,只是因为 Haskell 使用具有
unit
和bind
的 monad 定义,而其他的(fmap
,join
) 是从它们推断出来的。Haskell 的
bind
在 Fantasy Land Specification 中被命名为chain
因为bind
在 JavaScript 中违反了Function.prototype
,因此有人认为chain
足够接近。bind
即chain
“必须”返回相同类型的 monad 的原因是(>>=)::m a -> (a -> m b) -> m b
。简而言之,Haskell 的bind
函数必须只接受一个返回 monad 的函数(这部分a -> m b
),所以你得到它的结果。Haskell 的
then
is a mere convenience
和
sequences two monadic actions when the second action does not involve the result of the first, which is common for monads like IO.
实践中:
在 JS 中可能会让你感到厌烦,因为没有严格的类型强制,你总是可以不遵守规则并从
Promise
返回任何你想要的东西,例如,从而破坏所述 promise 的.then()
链。jQuery
等一些 monad 具有“提升”功能,作为始终返回jQuery
的方法,即相同类型,从而“保护”链接的能力。
关于javascript - JS Monad 单元函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/36099475/