我正在努力理解JavaScript中的单元函数。特别是因为让我'得到'monad(或至少我认为)的东西是Promise对象,以及then
如何总是返回一个新的Promise,无论你传递给then
的函数是什么,据我所知,相当于haskell中的bind
或>>=
。这对我来说是完全有意义的,因为它确保你所有的功能都在'monad universe'中执行,可以这么说。
道格拉斯·克罗克福德(Douglas Crockford)的“Monads and Gonads”演讲让我感到震惊。在他的实现中,bind
直接返回转换函数的结果,而不检查结果本身是否为monad。这与Promises的then
方法冲突,因为then
总是返回一个新的Promise。
一种想法是提升方法。他的实施确保'升力'将永远返回monad,并且可能then
被提升到Promise。但是,这意味着then !== bind
,并且Promise在某处具有内部绑定。
我的直觉是,在绑定函数中至少应该进行某种类型的检查,检查转换的结果,并允许生成的monad通过,但是会截取非monad并将它们传递给unit再次,就像'升力'一样。
*编辑
另外,我认为then
相当于bind, flatMap, >>=
,因为它有能力打开其他monad,包括不同的monad和它自己的类型。在查看JavaScript中的某些类别理论引用时,flatMap
用于映射一组嵌套数组,然后将它们展平为一维。这符合then
等待你提供的其他承诺的方式。但似乎与上面提到的原始实现不匹配。我感到迷茫。
任何拥有更多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
如何被重载,并根据你解决它的方式起到不同的作用。
此外,当我退后一步,看看Monads与常规仿函数有何不同时,很多东西都开始点击了。细节仍然有点模糊,但我认为我得到了全局。
一些有助于清除阴霾的好参考资料,
强烈推荐这个词用于高级概述,用人类的话来说
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
这两个参考文献特别为我创造了奇迹。希望能帮助其他人。
答案 0 :(得分:1)
我不太明白你的问题,但我会假设:
Monad的正确定义是什么,就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 Specification 中,这是of()
函数/方法。
第二个很重要,因为 Haskell 使用了unit
和bind
的monad定义,而其他人fmap
,{{1从它们推断形成它们。
Haskell的 join
在幻想土地规范中被命名为bind
,因为chain
在bind
上被视为Function.prototype
在 JavaScript 中,有人认为chain
足够接近。
bind
即chain
“必须”返回同一类型的monad的原因是因为
(>>=) :: m a -> (a -> m b) -> m b
。简而言之, Haskell的 bind
函数必须只接受一个返回monad的函数(这部分a -> m b
),所以你得到它的结果。
Haskell的 then
仅仅是方便
和
当第二个动作不涉及第一个动作的结果时,对两个monadic动作进行排序,这对于像IO这样的monad是常见的。
在实践中:
它可能会让你厌倦JS,因为没有严格的类型强制执行,你总是不能遵循规则并从Promise
返回你想要的任何东西,例如,因此打破了{{ 1}}所述承诺链。
像.then()
这样的一些monad已经“提升”了一些函数,它们总是返回jQuery
即相同类型的方法,从而“保护”链的能力。