## 模式匹配
模式匹配并不是什么新功能。而事实上它和函数式编程也没有什么太大的关系。它之所以常常被认为是FP的一个特性,是因为在函数式语言已经支持模式匹配很长一段时间后的今天,指令式语言是还没有这个功能。
还是直接用例子来看看什么是模式匹配吧,这是一个用Java写的Fibonacci函数:
~~~
int fib(int n) {
if(n == 0) return 1;
if(n == 1) return 1;
return fib(n - 2) + fib(n - 1);
}
~~~
再看看用我们基于Java修改过的新语言写出来的Fibonacci函数,这种新语言就支持模式匹配:
~~~
int fib(0) {
return 1;
}
int fib(1) {
return 1;
}
int fib(int n) {
return fib(n - 2) + fib(n - 1);
}
~~~
区别在哪里呢?在于后者的编译器替我们实现了程序的分支。
这有什么了不起的?确实也没什么。只是有人注意到很多函数中有非常复杂的switch结构(对于函数式程序而言更是如此),于是想到如果能把这层结构也抽象化就更好了。然后就把这个复杂的函数拆分成若干新的函数,并在这些函数的某些参数中应用模式(这和[重载](http://zh.wikipedia.org/wiki/%E5%87%BD%E6%95%B0%E9%87%8D%E8%BD%BD)有点类似)。这样依赖当这个函数被调用的时候,编译器会在运行时将调用者传入的参数与各个新函数的参数定义进行比较,找出合适的那个函数来执行。合适的函数往往是参数定义上最具体最接近传入参数的那个函数。在这个例子中,当n为1时,可以用函数int fib(int n),不过真正调用的是int fib(1)因为这个函数更具体更接近调用者的要求。
模式匹配一般来说要比这里举的例子更加复杂。比如说,高级模式匹配系统可以支持下面的操作:
~~~
int f(int n < 10) { ... }
int f(int n) { ... }
~~~
那么什么情况下模式匹配会有用呢?在需要处理一大堆程序分支的时候!每当需要实现复杂的嵌套if语句的时候,模式匹配可以帮助你用更少的代码更好的完成任务。我所知道的一个这样的函数是标准的WndProc函数,该函数是所有Win32应用程序必须具备的(尽管它经常会被抽象化)。模式匹配系统一般都可以像匹配简单数值一样匹配数据集合。举个例子,对于一个接受数组作为参数的函数,可以通过模式匹配数组中第一个数字为1并且第三个数字大于3的输入。 模式匹配的另外一个好处是每当需要添加或者修改程序分支时,再也不用面对那个庞大臃肿的函数了。只要添加(或者修改)相关的函数定义即可。有了模式匹配就不再需要四人帮的很多设计模式了。程序分支越多越复杂,模式匹配就越有用。而在习惯使用这一技术之后,你可能会怀疑没有它你一天都过不下去了。