promise is a monad?

Promise 是很好解决 js 异步的方案。

Monad 单子

Monad 是一个 FP 中的专有名词。
A monad is just a monoid in the category of endofunctors.
Monad 就是自函子范畴上的幺半群。

Functor 函子

在范畴论中,函子是范畴间的一类映射。函子也可以解释为小范畴内的态射。

态射是范畴内对象之间的映射关系。函子与它类似,函子是范畴与范畴间的映射关系,也就是可以通过一个函子,把一个范畴映射到另一个范畴。

可以将 Functor 理解成一个容器!
我们用 js 中的一些东西来解释一下可能更清楚。

const addThree = (x) => x + 3
const array = [ 2, 4, 6 ]
const mappedArray = array.map(addThree)
console.log(mappedArray)
// => [ 5, 7, 9 ]
functor

可以理解 Array 就是一个 Functor, 而 array 就是 Array 这个 Functor 的实例。

我们可以把 array 看成一个集合或者一个范畴。

  • array 里面的 2、4、6,应用了 addThree 与 mappedArray 中的 5、7、9 一一对应;

当然 Array 得是一个 Functor 的话,它还得满足 Functor 的其他特性,这里就不说了。

简单来说,函子就是一个可以将 function 应用到函子 value 的一个容器。

endoFunctor 自函子

把一个范畴映射到自身的函子叫做自函子。

假设我们现在把我们的范畴定义的更大一些,array 的元素是这个有理数集合,那么 Array 就是一个自函子。

现实中的自函子有哪些呢,挂钟就是一个自函子。

semigroup(半群) 与 monoid(幺半群)

google到数学里定义的群(group): G为非空集合,如果在G上定义的二元运算 *,满足

封闭性(Closure):对于任意a,b∈G,有a*b∈G
结合律(Associativity):对于任意a,b,c∈G,有(a*b)*c=a*(b*c)
幺元 (Identity):存在幺元e,使得对于任意a∈G,e*a=a*e=a
逆元:对于任意a∈G,存在逆元a^-1,使得a^-1*a=a*a^-1=e

如果仅满足封闭性和结合律,则称G是一个半群(Semigroup);如果仅满足封闭性、结合律并且有幺元,则称G是一个含幺半群(Monoid)。

比如自然数这个非空集合G,加上 + 这个二元运算,就是一个幺半群。(满足封闭性、结合律,0 就是幺元)

单子(Monad)是这样一个自函子范畴:

  • 其自函子对象是:
    M: C → C

  • 有以下两种自然变换:

    • unit(X): I → M X 是 C 中的对象,I 是 id 自函子
    • join(X): M × M → M

显然,在这个自函子范畴上构成了一个幺半群,这个幺半群的集合是所有自函子,其二元运算是由join决定结果的自函子复合。

在Haskell中的monad是这样的:

class Monad m where
    fmap    :: (a -> b ) -> f a -> f b
    return  :: a -> m a
    (>>= )  :: m a -> (a -> m b) -> m b

Promise 和 Monad

OK, 那 Monad js 中的 Promise 有什么关系呢?

haskell 中 Monad 是用来隔离副作用的,Promise 在 js 中也是用来隔离副作用的,所以我们本能可以将二者联系起来。

把 Promise 理解成一个容器。

  1. Promise.resolve(5) 或者 new Promise((resolve, reject) => resolve(6) 是不是就是 Monad 里面的 return 方法
  2. Promise.then 可以近似理解成 Monad 里面的 >>= 方法。
(pure 10 :: Maybe Int) >>= \x -> return (x * x)
Promise.resolve(10).then(x -> x * x)

Promise 和 Monad 不仅形似,而且神似。

那么再回过头讲讲 Monad。

Functor、Applicative 与 Monad

haskell GHC 7.8 重新定义了之前的 Functor、Applicative 与 Monad 的关系。

Functor ⟹ Applicative ⟹ Monad

那么看看 Applicative 是什么。

Applicative

Functor 的定义

class Functor f where
    fmap :: (a -> b) -> f a -> f b
class Functor f => Applicative f where
    (<*>) :: f (a -> b) -> f a -> f b

ps: <*> 就是 fmap

Functor 函子
fmap :: (a -> b) -> f a -> f b

Applicative 应用函子
(<*>) :: f (a -> b) -> f a -> f b

Applicative 必须是一个 Functor,而 Functor 只能将一个 value a 装进容器变成一个,然后与函数 a -> b 运算;
但是 Applicative 可以将函数 a -> b 装进容器,与原有的容器 f a 运算。

Applicative 与 Monad 的区别

[ x + y | x <- [1..3], y <- [1..x]]
-- [2, 3, 4, 4, 5 ,6]

[1..3] >>= \x -> [1..x] >> \y -> return (x + y)
-- [2, 3, 4, 4, 5 ,6]
(+) <$> [1..3] <*> [1..x]
-- Not in scope: 'x'

y 的取值是依赖于 x 的,使用 Monad 是可以的,但是使用 Applicative 是无法做到的!

也就是说 Monad 后面的计算可以依赖于前面计算的结果,但是 Applicative 中的每个参数的计算是独立的,后面的结果不能依赖于前面的。
通俗一些说 Monad 可以表达 上下文(context) 的计算,Applicative 是不可以的。

Monad在计算的时候,后一个计算问题可以用到前面的参数,也就是说各个计算之间不是互相独立的,而是有依赖关系的。

总结

同样的 Promise 是没有上下文的。

Promise.resolve([1, 2, 3])
.then(x => [1..x])
.then(y => (x + y))

ps: 上述 js 的例子部分是伪代码

个人觉得,从 Monad 的严格定义上, 很多约束条件 Promise 的实现都是没有满足或者没有严格满足,但是其形式及其相似。可以说 Promise is a monad;

然而,从 context 这个核心上来看,Promise 现有的实现不能满足。可以说 Promise is not a monad。

但是可以肯定的是 Promise 在隔离副作用上和 Monad 有异曲同工之妙。不知在确立 Promise 规范的时候,有没有借鉴 Monad!

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 199,064评论 5 466
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 83,606评论 2 376
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 146,011评论 0 328
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 53,550评论 1 269
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 62,465评论 5 359
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 47,919评论 1 275
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,428评论 3 390
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,075评论 0 254
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,208评论 1 294
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,185评论 2 317
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,191评论 1 328
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 32,914评论 3 316
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,482评论 3 302
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,585评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 30,825评论 1 255
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 42,194评论 2 344
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 41,703评论 2 339

推荐阅读更多精彩内容

  • 背景 所有一切的开始都是因为这句话:一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已,有什么难以理...
    福克斯记阅读 13,864评论 6 65
  • 梳理这些概念:group、semigroup、monoid、functor、endofunctor、combina...
    陈半仙儿阅读 1,837评论 2 5
  • Monad不就是个自函子范畴上的幺半群,这有什么难理解的(A monad is just a monoid in ...
    lambeta阅读 5,121评论 3 9
  • 一个单子(Monad)说白了不过就是自函子范畴上的一个幺半群而已,这有什么难以理解的?* 之前了解了下Monad,...
    纯白色固体阅读 1,195评论 1 1
  • 沉闷的雨夜,连呼吸都是压抑的。 将身抵住冰凉的墙壁,连同手指都用力撑着墙面尽量保持清醒,雨夜的水汽里还掺杂着淡淡的...
    夏禾真阅读 372评论 0 0