如何理解高阶函数

13,534 阅读3分钟

昨天开始读 SICP,这本书作为 MIT 所有理工科类学生的公共必修课(类似于咱们的高数),还是挺有价值的,很清楚的解释了一些基本概念,这里先总结一下高阶函数吧。

高阶函数的定义是接受一个函数作为参数,或者返回一个函数的函数。不过这样的解释作为总结也就罢了, 如果用来学习、理解的话。。。。。。还是看具体例子吧。

函数

我们知道函数是对过程的抽象,或者说是对某种过程的通用描述,比如说下面这个求绝对值的过程:

  • 5 -> |5| = 5
  • -1 -> |-1| = 1
  • 0 -> |0| = 0

求绝对值的过程是判断一个数是否大于等于 0,如果是的话,返回这个数,否则返回它的相反数。于是,为了对这个“复杂”过程进行抽象,我们可以定义一个函数 abs(x), 它专门用来计算一个数的绝对值。

可别小看这个貌似人人都会的简单的过程,它实际上是一件值得总结的事情,abs(x) 的价值绝不在于它实现求绝对值的过程,而是告诉我们:

如果有一系列操作,仅仅是输入的参数不同,但是对于参数的处理过程大致相同,我们就可以用函数来抽象这个操作。

求和

我们都熟练的掌握如何计算 1 到 n 中所有自然数的和,自然就可以定义一个函数 sum(a, b),表示从 a 到 b 中所有自然数的和,但如果被求和的不是自然数,而是某个表达式呢?

学过数学的人都知道,有一个符号叫求和符号,也即是这玩意:Σ,上述的 a 和 b 分别是它的上下标,后面还跟着一个函数 f(x)

Σf(x) = f(a) + f(a+1) + …… + f(b)

我们可以看到,Σ 也满足之前对函数的定义,首先它表示了一些列操作,随着输入参数(这时候是一个函数)的不同,它代表了不同的操作。但不管怎样,它对参数的处理方式总是类似的:依次把 a 到 b 中的每一个数代入到参数函数中,并且求和。

高阶函数

很多现代编程语言都实现了数组的 map 方法,它本质上就是一个高阶函数。为什么这么说,或者说为什么要在这里设计一个高阶函数呢?我们可以看一下 map 方法的本质:

for item in array:
item = handle(item)

你可以看到这个过程的变量其实是 handle 函数,也就是说 map 方法其实是对 “不同的 handle 函数的相似使用” 这一过程的抽象,因此它的参数必须是一个函数,这也就是为什么 map 是一个高阶函数。

同理,reduce 等也是高阶函数。

总结

高阶函数就是玩函数的,它把函数当做变量来用,回顾一下函数的定义:

如果有一系列操作,仅仅是输入的参数不同,但是对于参数的处理过程大致相同,我们就可以用函数来抽象这个操作。

这里并没有规定参数是什么,如果是一个数字,那我们可以理解为这是个普通函数;如果变量自身就是一个函数,我们可以理解为这是一个高阶函数。

不过我一直坚持的理念是,概念和名词只是用来简化、抽象某个具体的描述,它应该被用来方便人们进行交流而不是约束你的思维。所以高阶函数就是函数,不用做刻意的区分。