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);
}

返回结果为函数时,实际上返回的是该函数的闭包。

语言支持


References

1.First-class function


results matching ""

    No results matching ""