SICP中考题1.2->1.12是关于Pascal's triangle,如下图所示,初中数学就学过了。
SICP是以scheme作为讲解语言的,如果用Haskell来写这个Pascal's triangle会怎么样呢?程序会简短很多吗?(至少用C/C++/Java来写的话程序不会短)。
ft [x] = [x] ft (x:xs) = (x+(head xs)) : ft xs loop x 0 = [x] loop x n = [x]++loop (head x : ft x) (n-1) triangle1 n = loop [1] n
运行结果:
*Main> triangle1 6 [[1],[1,1],[1,2,1],[1,3,3,1],[1,4,6,4,1],[1,5,10,10,5,1]]
上面的haskell代码共5行, 可不可以让代码更紧凑一点呢?loop和ft函数可变为triangle的内部函数,这个SICP中scheme的思想一样。看看改进后的haskell代码:
triangle2 n = loop [1] n where loop x 1 = [x] loop x n = [x]++loop (head x : ft x) (n-1) ft [x] = [x] ft (x:xs) = (x+(head xs)) : ft xs
好了,现在只有一个triangle函数了,看起来比第一版好一些,但是代码行数没有减少,仍然是5行,还有优化的空间吗?
我们知道haskell是Lazy的functional语言,所以我们还可以对loop进行优化,看看第三版的haskell代码:
triangle3 n = take n (loop [1]) where loop x = [x]++loop (head x : ft x) ft [x] = [x] ft (x:xs) = (x+(head xs)) : ft xs
与第二版比较,第三版中的loop没有判断递归临界条件,那loop岂不变成了死循环了,这就是haskell的lazy特性的,loop的确会产生无限的list,但是我们仅使用前面的n个,所以这里使用take n。
triangle3的代码只有四行,比triangle2少了一行,还可以再减少行数吗?看看第四版的haskell代码:
triangle4 n = take n (loop [1]) where loop x = [x]++loop (head x : ft x) ft (x:xs) = if xs == [] then [x] else (x+(head xs)) : ft xs
同样我们优化了ft函数,使得ft的临界条件用判断语句加在ft的主题函数中,这样就又少了一行,现在的triangle4仅仅只有3行。
haskell由于善于处理这种数学问题,所以用haskell的思维来解决这类问题往往简单明了,相比这下,C/C++/Java则不是太适合来解决这种问题了,用C/C++/Java你是不可能用3行代码就解决Pascal's triangle的。