12.1 什么是函数

在数学中,函数指的是两个非空集合之间的一种对应关系。例如,有这样一个函数:

  1. f(x) = x + x

对此,我们输入1就一定会得到2,输入2就一定会得到4,输入3就一定会得到6,等等。

只要我们给予一个函数的输入值是确定的,那么它的输出值就一定也是确定的。即使我们还不知道那个输出值是什么,也是如此。所以,在使用者看来,函数就像一个黑箱。只要我们给予它一个或一组参数,它就会为我们返回一个结果。如果我们想要知道一个函数具体都做了些什么,就只能去查看和理解它的内在了。

另外,数学中的函数还有着如下特性(或者说规则):

  1. 只要有输入,就一定会输出。也就是说,对于每一个有效的输入值,函数都会返回一个输出值。
  2. 输入值与输出值之间的对应关系是固定的。我们刚刚说过,输入值确定就意味着输出值确定。而现在我们还可以进一步明确,对于同一个函数,相同的输入值总是会产生相同的输出值。
  3. 输入值与输出值之间可以是多对一的关系。换句话讲,多个或多组输入值可能会产生相同的输出值。但是,同一个或同一组输入值绝对不可能产生不同的输出值。你可以考虑一下f(x,y) = x + y这个函数。

显然,数学中的函数定义是非常严谨的。它可以保证每一个函数的有效性和稳定性。相比之下,程序设计领域对于函数这一概念的诠释就比较丰富多彩了。这主要是因为,各种编程语言都会结合自身的特点来确定“函数”的地位、用途以及功能。

比如,在一些崇尚函数式编程(functional programming)的编程语言中,尤其是那些纯粹的函数式编程语言,其函数的定义方式就非常贴近于数学中的函数。而在一些混合式的编程语言中,函数的定义可以是非常灵活的。这些函数可以有自己的副作用(side effects),甚至可以没有输出值以及输入值。此外,一些倡导面向对象编程(object oriented programming)的编程语言会弱化函数这个概念。在这种程序中的所谓函数只能被定义成对象或者类型的附属品,而不能独立的存在。

我在这里再解释一下刚刚提到的一些概念。它们对于你来说可能会比较陌生。函数的副作用是指,除了返回输出值之外,函数对外界产生的其他影响。比如,修改传入的参数值、修改某个全局的变量或状态(同时也可能会受到其影响)、向计算机的标准输出(也就是 stdout)打印内容,等等。拥有副作用的函数肯定就不能被称为纯粹的函数了。但是,在很多时候这种函数的存在也是很有必要的。另外,函数式、混合式和面向对象指的都是编程语言所支持的编程范式(programming paradigm)。其中,混合式的意思是,编程语言对函数式、面向对象甚至其他的编程范式都提供了一定程度上的支持。这样的编程语言也常常被称为多范式语言。

我早在第一章就说过,Julia 是多范式的编程语言。而且,它是明显倾向于函数式的。函数在 Julia 语言中绝对有着举足轻重的作用和地位。这也是我之前一直在陆续地讲述 Julia 函数相关知识的主要原因。