实际使用高阶函数的关键是您需要 闭包:一个普通的旧 C 函数除了其参数之外,只能使用全局/静态数据。这意味着类似
GHCi> 过滤器 (>4) [7,4,3,6,87,5,4]
[7,6,87,5]
不能真正工作,除非你全局定义
bool largerThan4(int i) {return (i>4);}
这显然无法扩展。没有办法从程序中的其他地方“注入”数字 4。函数式语言将此类信息封装在闭包中。
现在,这个 GNU C 扩展在有限的意义上为您提供了闭包,我认为这与 C++11 defines for lambdas capturing by reference 的含义相同:本地函数可以引用其包含范围内的变量。比如说,这很有效,
typedef std::vector<int> IntArray;
IntArray filter (const IntArray& a, std::function<bool(int)> pred) {
IntArray result;
for(auto& i: a) if (pred(i)) result.push_back(i);
return result;
}
int main() {
std::vector<int> v{{7,4,3,6,87,5,4}};
int minNumber = 4;
for(auto i: filter(v, [&](int i){return i>minNumber;}))
cout << i << endl;
return 0;
}
(在没有范围循环等的 C 中,这当然会更麻烦。)这里,本地匿名函数仅在 minNumber 仍然是 main 的范围时使用,所以 filter 保持在调用那个谓词时,它总是可以指向那个位置。
但这是一个非常简单的场景。在函数式语言中,您通常会更普遍地使用高阶函数,包括诸如
- 从另一个函数返回一个函数。这已经是词法闭包的问题了——你不能在局部变量离开作用域后引用它!因此,您需要将该变量复制/移出作为额外回报。
- 在闭包中使用来自其他闭包本身的变量,您无法直接控制这些变量。闭包不能无限期地存在,它们需要在某个时候被擦除——但是编译器怎么知道它什么时候是安全的呢?函数式语言通常是垃圾回收的,这就解决了这个问题。
- 以自身为参数的函数递归。这意味着可以有效地存在变量引用循环 ("tying the knot")。这通常意味着程序将挂起,除非您进行惰性评估。