Functor、Applicative 和 Monad 是函数式编程语言中三个非常重要的概念,尤其是 Monad ,难倒了不知道多少英雄好汉。事实上,它们的概念是非常简单的,但是却很少有文章能够将它们描述清楚,往往还适得其反,越描越黑。与其它文章不同的是,本文将从结论出发,层层深入,一步步为你揭开它们的神秘面纱。
说明:本文中的主要代码为 Haskell 语言,它是一门纯函数式的编程语言。其中,具体的语法细节,我们不需要太过关心,因为这并不影响你对本文的理解。
结论
关于 Functor、Applicative 和 Monad 的概念,其实各用一句话就可以概括:
-
一个 Functor 就是一种实现了 Functor typeclass 的数据类型;
-
一个 Applicative 就是一种实现了 Applicative typeclass 的数据类型;
-
一个 Monad 就是一种实现了 Monad typeclass 的数据类型。
当然,你可能会问那什么是 typeclass 呢?我想当你在看到实现二字的时候,就应该已经猜到了:
A typeclass is a sort of interface that defines some behavior. If a type is a part of a typeclass, that means that it supports and implements the behavior the typeclass describes. A lot of people coming from OOP get confused by typeclasses because they think they are like classes in object oriented languages. Well, they’re not. You can think of them kind of as Java interfaces, only better.
是的,typeclass 就类似于 Java 中的接口,或者 Objective-C 中的协议。在 typeclass 中定义了一些函数,实现一个 typeclass 就是要实现这些函数,而所有实现了这个 typeclass 的数据类型都会拥有这些共同的行为。
那 Functor、Applicative 和 Monad 三者之间有什么联系吗,为什么它们老是结队出现呢?其实,Applicative 是增强型的 Functor ,一种数据类型要成为 Applicative 的前提条件是它必须是 Functor ;同样的,Monad 是增强型的 Applicative ,一种数据类型要成为 Monad 的前提条件是它必须是 Applicative 。注:这个联系,在我们看到 Applicative typeclass 和 Monad typeclass 的定义时,自然就会明了。
Maybe
在正式开始介绍 Functor、Applicative 和 Monad 的定义前,我想先介绍一种非常有意思的数据类型,Maybe 类型(可类比 Swift 中的 Optional):
The Maybe type encapsulates an optional value. A value of type Maybe a either contains a value of type a (represented as Just a), or it is empty (represented as Nothing). Using Maybe is a good way to deal with errors or exceptional cases without resorting to drastic measures such as error.
Maybe 类型封装了一个可选值。一个 Maybe a 类型的值要么包含一个 a 类型的值(用 Just a 表示);要么为空(用 Nothing 表示)。我们可以把 Maybe 看作一个盒子,这个盒子里面可能装着一个 a 类型的值,即 Just a ;也可能是一个空盒子,即 Nothing 。或者,你也可以把它理解成泛型,比如 Objective-C 中的 NSArray。不过,最正确的理解应该是把 Maybe 看作一个上下文,这个上下文表示某次计算可能成功也可能失败,成功时用 Just a 表示,a 为计算结果;失败时用 Nothing 表示,这就是 Maybe 类型存在的意义:
data Maybe a = Nothing | Just a
下面,我们来直观地感受一下 Maybe 类型:
ghci> Nothing Nothing ghci> Just 2 Just 2
我们可以用盒子模型来理解一下,Nothing 就是一个空盒子;而 Just 2 则是一个装着 2 这个值的盒子:
提前剧透:Maybe 类型实现了 Functor typeclass、Applicative typeclass 和 Monad typeclass ,所以它同时是 Functor、Applicative 和 Monad ,具体实现细节将在下面的章节进行介绍。
Functor
在正式开始介绍 Functor 前,我们先思考一个这样的问题,假如我们有一个值 2 :
我们如何将函数 (+3) 应用到这个值上呢?我想上过小学的朋友应该都知道,这就是一个简单的加法运算: