【IT168 技术文档】到现在我们已经讲了不少东西了,但我们还没有真正涉及到函数式编程. 目前所讲的所有特性 - 丰富的数据类型(rich data types), 模式匹配(pattern matching), 类型推导(type inference), 嵌套函数(nested functions) - 可以想象它们都可以在一种”超级C“语言中存在。这些特性当然很酷,它们使得代码简洁易读,减少bug,但是它们实际和函数式编程没什么关系。实际上我的观点是函数式编程语言的妙处不是在于函数式编程,而是因为在我们长年习惯于类C语言编程的时候,编程技术已经提高很多了。因此当我们一次又一次地写struct { int type; union { ... } }的时候,ML和Haskell程序员却有着很多安全的变量和数据类型的模式匹配。当我们小心翼翼地 free所有的malloc时候,很多语言在上世纪八十年代就有了超越手工管理的内存垃圾收集器。
好了,现在是时候告诉你们什么是函数式编程了。
基本的不是很能说明问题的定义是在函数式语言中, 函数(functions)是一等公民。
听上去不是很有用,让我们来看个例子。
# let double x = x * 2 in List.map double [ 1; 2; 3 ];; - : int list = [2; 4; 6]
在这个例子中,我首先定义了一个嵌套函数double,它读入一个参数x后返回x * 2。然后map在给定的列表([1; 2; 3])的每个元素上调用double来生成结果:一个每个数都扩大一倍的新的列表。
map被称为高阶函数(higher-order function) (HOF)。高阶函数是指一个把其他函数作为参数之一的函数。
到现在为止还算简单。如果你对C/C++熟悉的,这就象传递一个函数指针作为参数。Java中有匿名类(anonymous class)就象一个低速的闭包(closure)。如果你知道Perl那么你可以已经知道和使用了Perl中的闭包和Perl的map函数,这和我们现在所说的完全相同。事实上Perl很大程度上也是一个函数式语言。
闭包是那些带着它们被定义时的环境的函数。特别的,一个闭包可以引用它定义时存在的变量。让我们把上面那个函数变得更通用一些,以便我们可以对任何整数列表乘以一个任意值n:
let multiply n list = let f x = n * x in List.map f list ;;
因此:
# multiply 2 [1; 2; 3];; - : int list = [2; 4; 6] # multiply 5 [1; 2; 3];; - : int list = [5; 10; 15]
关于multiply函数有一点值得注意的是嵌套函数f. 这是一个闭包。我们注意一下f怎样使用变量n的值,我们并没有把n作为显式的参数传递给它。f是从它的环境中找到它的。n是传递给函数multiply的参数,所以在这个函数中都是有效的。
| 第1页: 什么是函数式编程 |