一、迷失于Monad的汪洋大海
第一次看见这个概念是两年前,这个词有着非常不通俗的翻译:“单子”。那时候受王垠影响在看Scheme和Haskell,对于Scheme的continuation和Haskell的Monad百思不得其解。直觉告诉我,这俩货之间有着千丝万缕的联系。当时对于类型可计算的概念也是毫无概念,作为刚从Java Web转到程序语言研究的我真是菜的不行,如饥似渴的在网上找资料各种读,越读越迷惑,后来不得不放下。
二、和Monad的几个照面
而后自己写了几个很菜的编译器,和性能啊新特性啊什么的毫不沾边。
看别人博客的文章照猫画虎也写过Monadic的语法分析器,也用过C#大法的Linq,然而并没有使我明白Monad是个啥。
Linq中的
from a in A
from b in B
from c in C
select f(a,b,c)
其实可以转化为这种结构:
A.SelectMany(a=>
B.SelectMany(b=>
C.Select(c=> f(a,b,c)
)
)
);
再后来在深入浅出node.js里见识了js的嵌套callback,因此看到了promise。
嵌套callback的代码:
A.fuck1(function(a){
B.fuck2(function(b){
C.fuck3(function(c){
f(a,b,c);
}
}
});
promise把嵌套callback改写成这种风格(大概,伪代码):
Promise.then(A.fuck1)
.then(B.fuck2)
.then(C.fuck3)
.then(function(a,b,c){
f(a,b,c);
})
.done();
当时读来毫无感觉,现在细想毛骨悚然。
熟悉Scheme的孩子应该一眼就能发现这里面有CPS变换。
所谓CPS变换就是把所有g(f(x))都给改写成f(x, r=>g(r))的过程。然而这有和Monad有什么关系?Monad到底是个啥?
CPS变换和Monad是一家亲。CPS变换是说变换过程,而Monad是具备某种能力的“对象”。所谓具备某种能力其实就是Monad具备这种把嵌套式的金字塔结构打平成链式结构的能力。Promise差不多算是和Linq有异曲同工之妙。两者都是Monad的应用。Monad的定义涉及了一些类型计算,其实是很简单的东西,只是写成学术符号立刻让人看不懂了。
最近读了一篇文章联想起之前的Linq和promise,仿佛是有点恍然大悟的感觉。
在Swift里,“一个实现了 flatMap方法的类型其实就是 monad”。
public func flatMap(f: (Wrapped) -> U?) -> U? {
switch self {
case .Some(let y): return try f(y)
case .None: return .None
}
}
flatMap接受一个函数f做参数,返回一个Optinal U类型。f接受Optional类型包裹的类型,返回Optinal U类型。
下面是Optional的定义:
enum Optional {
case None
case Some(T)
}
这只是一个很小的关于Optianal
当然Monad可不仅仅是这样,当年在Haskell里面反正是看的云里雾里。熟悉类型推导的孩子可以推导一下类型,看看为毛promise可以写成那样。哦,我忘了,js是弱类型的!
其实这篇文章我倒没打算把Monad讲明白,因为毕竟我是跌跌撞撞走过了很多弯路才明白了类型计算,continuation才最终走到了Monad面前,不敢说自己有什么理解,只是通俗的明白了这货原来真的有用,而且用的还不少,只是学术性太强导致曾经看过的资料总有些说不清道不明,感觉有道鸿沟横在眼前。
之所以写这篇是因为我知道这个概念太久,如鲠在喉。
贴上两篇有启发的文章:
http://www.infoq.com/cn/articles/swift-brain-gym-monad?utm_campaign=rightbar_v2&utm_source=infoq&utm_medium=articles_link&utm_content=link_text
http://www.cppblog.com/vczh/archive/2013/07/27/202154.html
最后感慨一下,vczh大神的高度果然不是我这等渣渣可以企及的。当年太菜没看懂几篇vczh的博客,泪流满面。