模式匹配大法好
6/Sep 2014
if, while, for
除了Hello,world之外的任何程序,几乎都离不开控制结构。比如if-then-else, while,for,其实这三种的基础说白了还是加了一层语法塘的goto语句。不过相比直接使用goto而言,程序的流程走向更容易被程序员掌握。for主要用于重复次数明确的情形,while在循环条件已知时很合适。由于二者完全是在做同样的事情,以至于Rob Pike在Go中统一命名为for。
如果每天只能重复地做一件事,世界会变地多么乏味。。。所以我们需要更多的选择,更多的种类。真实世界是纷繁复杂的,我们无时无刻不面临着选择。编程语言处理选择问题,最常见的就算if-then-else, 其实这个结构最早来源于lisp语言。 if-then-else是一种显式的选择方式,提醒程序员下个路口再见吧:
if A = 1:
return "positive"
elif A = -1:
return "negative"
else:
return "abnormal"
其实在做选择的时候,我们已经知道这是一个选择问题,不必在文字上再次提醒这里面临着一个选择,如果……则……那么……, 即我们可以把if, then, else这样的字眼給省略掉:
A :=
1 -> "positive"
-1 -> "negative"
_ -> "abnormal"
这种简洁的选择方式和if-then-else是等价的,这种表达方式来自于ML, 一般称之为模式匹配
。简洁带来的好处一是代码上的整洁,舒适。 二是把很多dirty的细节隐匿起来,直达问题本身,这样我们就可以前进的更快,想象力就会飘的更远。。。举个快速排序的栗子:
命令式语言 Go实现
func partition(A []int, low int, high int) int {
x := A[high]
i := low - 1
for j := low; j < high; j++ {
if A[j] <= x {
i++
A[i], A[j] = A[j], A[i]
}
}
A[i+1], A[high] = A[high], A[i+1]
return i + 1
}
func quickSort(A []int, low int, high int) {
if low < high {
p := partition(A, low, high)
quickSort(A, low, p-1)
quickSort(A, p+1, high)
}
}
func QuickSort(A []int) {
quickSort(A, 0, len(A)-1)
}
不带模式匹配的Lisp Scheme实现
(define (qsort lst)
(if (<= (length lst) 1)
lst
(append (qsort (filter (cdr lst) (lambda (x) (<= x (car lst)))))
(cons (car lst) (qsort (filter (cdr lst) (lambda (x) (> x (car lst)))))))))
带模式匹配的语言 Erlang实现
qsort([]) -> [];
qsort([Pivot|T]) ->
qsort([X || X <- T, X < Pivot])
++ [Pivot] ++
qsort([X || X <- T, X >= Pivot]).
显而易见,自带模式匹配的语言在屏蔽了语言细节之后,直接把快速排序的本质勾勒了出来,简单粗暴且自带闪光灯!!! 为什么仅仅是省略了选择相关的字眼,生产率以及通俗性提高那么多呢? 我猜测的原因如下:
人是一种害怕做选择的动物,尤其是意识到自己面临选择的时候。使用if-then-else好比是在做选择的时候告诉程序员:Hi,SB, you should make a choice! 是不是还有点细思极恐???!!!而使用模式匹配,似乎只需要制定好一条条规则, Let the compiler do the fuck choice! 对于选择困难综合症的朋友来说,真是居家旅行,杀人越货必备之良器。
总结来说,简洁的事物之所以有时候威力更强大,是因为简洁的重点不是简,而是洁。 隐匿了冗余的细节,减轻了思想上的包袱,让程序员可以轻装上阵,专注于真正的问题,谓之“洁”。
所以, 如果存在最好的语言,她不一定是最简单的语言,但一定是最简洁的语言。