[fwd]什么是Monad?

发信人: faint (faint), 信区: FuncProgram
标  题: 什么是Monad(1): introduction
发信站: 水木社区 (Sun Oct  8 05:06:47 2006), 站内

在函数式编程里面,Monad是一个门槛。但是要解释“什么是monad”,这世界上没几个人
能一下讲清楚,因为涉及的背景知识太复杂。

介绍Monad可以被认为是一个"industry job":如果你能一下说清楚,就可以去当教授。

下面我说说我个人的从程序员角度的理解,目的不在于介绍monad的技术细节,而在于介
绍monad的背景和相关知识环境。

(基本概念:combinator/combinator programming/combinator language)

首先,函数式编程可以让我们方便的使用高阶函数(higher-order functions)写出很通用
的程序部件,比如map, fold, filter, \x->[x], 等等,这些函数组合性质和重用性都很
好,里面没有free variable,可以把这样的函数叫做"combinator"。

在程序里大量使用combinator就产生了一种编程风格,叫做"combinator programming"。
这种编程风格对于给定的问题定义几个combinator,然后拿这几个combinator当作一个“
语言”,把它们组合起来写程序。我们把这样由combinator构成的语言叫做"combinator
language"。

下面举几个combinator language例子:

例子1: 用map/fold/join/filter/unit这几个基本函数组合起来就可以写出很复杂的list
处理程序。

例子2: 函数式编程的状态经常要作为参数传递很麻烦, 就有人定义了所谓的"state
monad", 用几个基本的combinator部件来处理状态: return, bind, get, put

例子3: 一个很常见的应用就是所谓的"combinator parsing". 每一个基本的combinator
就是一个简单的parser, 只负责parse基本的语法单位, 比如我定义一个函数"word"来
parse一个词, 定义一个函数"number"来parse一个数字, 再定义一个函数"then"来组合各
种parser. 然后我就可以通过组合这些基本的函数来构造复杂的parser: "word then
number".

例子4: 最极端的例子是SK combinators,这两个函数组合起来跟图灵机等价,只用S和K
就可以编出一切程序.

(Generic combinator interfaces)

Combinator programming就像搭积木,用一些函数构造基本的积木块,再用一些组合性质
比较好的函数来连接各个模块,就像LEGO积木一样。人们编程经验很多以后,就总结出一
些基本的通用的设计模式,这些通用模式在很多combinator language中都适用。下面
要提到的Monad就是其中一个。

(Monad, monadic language)

Monad是一个通用的combinator interface。到底什么算是一个monad呢?如果我定义了一
个combinator language,里面有两个基本部件"return"和">>=",而且这两个部件满足以
下的组合性质,就可以说这个combinator language是一个monad:

   1. (return x) >>= f == f x
   2. m >>= return == m
   3. (m >>= f) >>= g == m >>= (\x -> f x >>= g)

这两个基本部件的意义其实很简单:return构造一个基本的"积木块",而(>>=)把各个积
木块顺序连接起来。如果一个combinator language里面有这样的基本结构,就可以说它
是一个monad,可以说这个language是一个monadic language。

由于monad有很好的组合性质,可以很容易的表达程序的控制结构,它成为很多
combinator language的设计方案。具体的例子很多,比如identity monad, maybe
monad, state monad, CPS monad,monadic parser combinators, 等等,都是经典的
monadic language。如果我想设计一个combinator language,首先就会想能不能设计
成一个monad。

(Monadic programming style)

如果我们设计的combinator language是一个monad,编出来的程序都会有一种特定的风格
:用return构造基本的积木块,用(>>=)组合各个模块。比如说,在Haskell的IO monad里
面我们可以写这么一段程序:
  return stdin   >>= (\h1 ->
  return stdout  >>= (\h2 ->
  hGetChar h1    >>= (\x ->
  hPutChar h2 x  >>= (\_ ->
  hPutChar h2 x ))))

实现的功能就是从stdin里面读入一个字符x,然后把它往stdout里面输出两次。可以看到
,通过使用return, >>=和匿名函数就可以实现复杂的variable binding。

(Monads in Haskell)

如果用其他的编程语言,上面的介绍就足够了。Haskell对Monad提供了更好的支持,可以
让基于Monad的编程更简单!具体有以下两点:

1. Type class。在Haskell里,可以把Monad定义成为一个type class,提供两个标准操
作:return和>>=。这样,不同的monad都可以重载这两个操作,让所有基于monad的程序
看上去都是相同的!

2. Do-syntax。既然type class可以让所有的monad程序都有相同的界面,只要让编译器
把这个界面化简一下,就相当于化简了所有monad界面。Haskell提供了一个"do-syntax"
,极大的简化了前一节提到的monadic programming style。比如说,前一节的程序可以
写为:
  do { let h1 = stdin
           h2 = stdout
       x <- hGetChar h1
       hPutChar h2 x
       hPutChar h2 x
     }

在编译的时候,这个使用do-syntax的程序会被翻译成前一节的基于return和>>=的程序。
现在看来,易读性已经和C/Java编程差不多了。。。

你可能感兴趣的:(设计模式,编程,F#,haskell,sun)