First-Class Function
头等函数(first-class function)是指在程序设计语言中,函数被当作头等公民。这意味着,函数可以作为别的函数的参数、函数的返回值,赋值给变量或存储在数据结构中。
1960年代中期,克里斯托弗·斯特雷奇在“functions as first-class citizens”中提出匿名函数的概念。即在编程语言中函数的名字没有特殊含义,它们被当作具有函数类型的普通的变量对待。
头等函数是函数式编程所必须的。通常要使用高阶函数。
把函数作为函数参数与函数返回值会遇到特别的困难。特别是存在非局部变量与嵌套函数、匿名函数。历史上,这被称作函数参数问题。早期的命令式编程语言,或者不支持函数作为结果类型(如ALGOL 60, Pascal),或者忽略嵌套函数与非局部变量(如C语言)。早期的函数式语言Lisp采取了动态作用域方法,把非局部变量绑定到函数执行点最近的变量定义。Scheme语言支持词法作用域的头等函数,把对函数的引用绑定到闭包(closure)而不是函数指针,这使得垃圾收集成为必须。
高阶函数
高阶函数的特点为,至少满足下列一个条件的函数:
- 接受一个或多个函数作为输入
- 输出一个函数
一个Python script的例子
def f(x):
return x + 3
def g(function, x): //形参为函数
return function(x) * function(x)
print g(f, 7)
匿名函数与嵌套函数
JavaScript支持匿名函数。
alert((function(x){
return x*x;
})(10)); // 提示100
C语言不支持匿名函数。
main() {
...
}
void func( void ) {
static int i = 5;
printf("i is %d ", i);
}
非局部变量与闭包
一旦有了匿名函数与嵌套函数,引用函数体之外的变量(非局部变量)就很自然了:
main = let a = 3
b = 1
in map (\x -> a * x + b) [1, 2, 3, 4, 5]
如果函数只能用函数指针表示,如何把函数体之外的值传递给函数就是个问题。可以手工建立一个闭包,但显然这不能算作头等函数.
typedef struct {
int (*f)(int, int, int);
int *a;
int *b;
} closure_t;
void map(closure_t *closure, int x[], size_t n) {
for (int i = 0; i < n; ++i)
x[i] = (*closure->f)(*closure->a, *closure->b, x[i]);
}
int f(int a, int b, int x) {
return a * x + b;
}
void main() {
int l[] = {1, 2, 3, 4, 5};
int a = 3;
int b = 1;
closure_t closure = {f, &a, &b};
map(&closure, l, 5);
}
返回结果为函数时,实际上返回的是该函数的闭包。
语言支持
