2.12 函数式编程 (Functional Programming)

函数式编程意味着撰写利用返回值而工作的程序,而不是修改东西。它是 Lisp 的主流范式。大部分 Lisp 的内置函数被调用是为了取得返回值,而不是副作用。

举例来说,函数 remove 接受一个对象和一个列表,返回不含这个对象的新列表:

  1. > (setf lst '(c a r a t))
  2. (C A R A T)
  3. > (remove 'a lst)
  4. (C R T)

为什么不干脆说 remove 从列表里移除一个对象?因为它不是这么做的。原来的表没有被改变:

  1. > lst
  2. (C A R A T)

若你真的想从列表里移除某些东西怎么办?在 Lisp 通常你这么做,把这个列表当作实参,传入某个函数,并使用 setf 来处理返回值。要移除所有在列表 xa ,我们可以说:

  1. (setf x (remove 'a x))

函数式编程本质上意味着避免使用如 setf 的函数。起初可能觉得这根本不可能,更遑论去做了。怎么可以只凭返回值来建立程序?

完全不用到副作用是很不方便的。然而,随着你进一步阅读,会惊讶地发现需要用到副作用的地方很少。副作用用得越少,你就更上一层楼。

函数式编程最重要的优点之一是,它允许交互式测试(interactive testing)。在纯函数式的程序里,你可以测试每个你写的函数。如果它返回你预期的值,你可以有信心它是对的。这额外的信心,集结起来,会产生巨大的差别。当你改动了程序里的任何一个地方,会得到即时的改变。而这种即时的改变,使我们有一种新的编程风格。类比于电话与信件,让我们有一种新的通讯方式。