模式匹配大法好

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! 对于选择困难综合症的朋友来说,真是居家旅行,杀人越货必备之良器。

总结来说,简洁的事物之所以有时候威力更强大,是因为简洁的重点不是简,而是洁。 隐匿了冗余的细节,减轻了思想上的包袱,让程序员可以轻装上阵,专注于真正的问题,谓之“洁”。

所以, 如果存在最好的语言,她不一定是最简单的语言,但一定是最简洁的语言。

More Reading