Versions:2009-01-01 2013-04-21 2014-02-10 2014-04-21 2014-06-21 2015-12-05 2016-09-22 2017-05-04 2017-10-25 2017-12-03 2018-02-22 2019-12-08 2020-02-28 2024-04-16

对函数式语言的误解

很早的时候,“函数式语言”对于我来说就是 Lisp,因为 Lisp 可以在程序的几乎任何位置定义函数,并且把它们作为值来传递(这叫做 first-class function)。后来有人告诉我,Lisp 其实不算是“函数式语言”,因为 Lisp 的函数并不“纯”(pure)。所谓“纯函数”的意思,就是像数学的函数一样,如果你给它同样的输入,它就给你同样的输出。然后你就发现在这种定义下,几乎所有程序语言里面常见的随机数函数(random),其实都不是“纯函数”。因为每一次调用 random(),你都会得到不同的随机数。

在这种害怕自己所用的语言“不纯”的恐慌之下,我开始接触 Haskell,一种号称“纯函数式”的语言。Haskell 的社区喜欢在他们的概念里省掉“纯”这个字,把 Haskell 叫做“函数式语言”。他们喜欢“纠正”别人的概念。他们告诉人们,“不纯”的函数式语言,其实都不配叫做“函数式语言”。在他们的这种定义下,Lisp 这么老牌的函数式语言,居然都不能叫“函数式语言”了。但是看完这篇文章你就会发现,其实他们的这种定义是狭隘和错误的。

在 Haskell 里面,你不能使用通常语言里面都有的赋值语句,比如 Pascal 里的 x:=1,C 和 Java 里的 x=1,或者 Scheme 里的 (set! x 1),Common Lisp 里的 (setq x 1)。这样一来,你就不可能保留“状态”(state)。所谓“状态”,就是指“随机数种子”那样的东西,其实本质上就是“全局变量”。比如,在 C 语言里定义 random() 函数,你可以这么做:

int random()
{
  static int seed = 0;
  seed = next_random(seed);
  return seed;
}