时间的秩序,萨特,与函数式编程

137 阅读10分钟

前面的文章《泰勒斯,欧几里得,与结构化编程》中,我们讲到,结构化编程就像希腊早期自然哲学一样,努力寻找时间意义上的本原,让万事万物归于秩序。希腊人找到了火,气,水,土这四种构成自然世界的基本元素,而程序员找到了顺序,分支,循环这三种程序世界的基本结构。

《柏拉图与面向对象编程》这一文中,我提到,面向对象这一编程思想,跟柏拉图的理念论不谋而合。柏拉图把世界分为『可感世界』和『理念世界』。『可感世界』可感而不可知,『理念世界』可知而不可感。同时,不同的理念也是可以相互结合和分有的。这跟面向对象里面的类,接口,继承,实现等相关概念是十分相似的。

现在,我们看看另一个流行的编程范式—— 函数式编程。

1

先复习一下什么是函数式编程。熟悉的同学可以跳过这一部分。

下面这个例子来自《架构整洁之道》。

如果我想要输出前 25 个整数的平方值,用 Java 写的话,代码是这样的:

public class Squint { 
    public static void main(String args[]) { 
        for (int i = 0; i < 25; i++) { 
            System.out.println(i * i) 
        } 
    } 
}

如果用一个纯函数式的语言 Clojure 来写这个程序,是这样的:

(println (take 25 (map (fn [x] (* x x)) (range))))

Java 的写法我就不过多解释了,基本上学过编程的都能看懂。重点讲一下这个 Clojure。

在 Clojure 里面,函数调用都是通过括号来进行的,比如上面的第一个函数(println),这跟我们 Java 或者其他语言有点不同,其他的更多的是括号在后面,比如println()这样。

参数的传递则直接跟在后面,比如 (println "Hello World!"),可以看到,大部分函数都可以接收另一个函数作为参数。比如(println (range))

匿名函数用fn来声明。就像上面的(fn [x] (* x x)),其中的 [x]代表该匿名函数的入参,第二个 (* x x)代表调用乘法函数,将两个数相乘,这两个数都是 fn 的入参x

再解释一下这几个函数是什么意思。

  • println是打印输出的意思。

  • take是取列表中的前n个元素。

    它的第一个参数是要取几个元素,第二个参数是要取的列表或者可以返回一个列表的函数。

  • map是将一个输入值转换为输出值的函数,它有两个参数,第一个参数是一个转换函数,这个转换函数会把一个输入值转化为输出值,就是上面提到的fn,第二个参数是数据源,就是转换函数输入值的提供者。

  • fn前面已经解释过,是一个用来计算平方值的匿名函数

  • range是一个返回从 0 开始的整数无穷列表的函数。

    是这一系列函数调用的数据源。

那么,这段代码翻译成自然语言就是,取一个无穷整数列表(range),对列表中的元素(map)依次求平方值(fn),并将前 25 个结果(take)输出打印(println)出来。

这个无穷整数列表不需要担心,因为这个列表中的元素只有真正被访问到的时候才会被创建。所以最终只会有 25 个元素被创建。

它跟结构化或者面向对象有什么不同呢?

在 Java 里面,我们使用到了可变量,就是i,它在一个循环之中不断被改变值。不断被赋予新的使命去完成下一个任务。但是在 Clojure 里面,没有任何值被改变,只有一个变量在一系列的函数之中产生另一个变量,另一个变量再通过函数产生其他变量。注意,我这里说的是『产生』,而不是『变成』。这些变量没有被改变,它被用完,就丢弃了,等着垃圾回收器来回收。

于是我们就知道了函数式编程的最大特点:变量,是不可变的。

这又有什么好处呢?

一个显而易见的好处就是,所有因为并发导致的状态不同步问题,都不会存在了。因为状态变量不会被改变,所以你可以放心使用。你也不能妄想改变这个变量的值,就不需要有锁的存在。所有死锁问题也就迎刃而解。

好了,函数式编程就先介绍到这里,有兴趣深入的同学可以自行去查资料。下面我们看看函数式编程的哲学思考。

2

函数式编程,让我想到了萨特的存在主义。

萨特存在主义的核心思想是,人的存在先于本质。

这句话什么意思呢?举个例子。拿一个杯子来说,在杯子被造出来之前,杯子的本质其实已经形成了,它就会长得跟设计师的图纸一致,并且会被用来装水。这在它被生产出来之后都不会改变。我们就可以讲,这个杯子的本质,是先于存在的。那如果,我只是造一个一端被封住的中空圆柱体。在造它的时候,我并不知道用它来做什么。它被造出来之后,我用它来盛水,它就成了杯子,我用它来种花,它就成了花盆,我用它来解决夜晚的燃眉之急,它就成了夜壶。对这个中空圆柱体来说,它的存在就是先于本质的。

人就是存在先于本质的。没有人生下来就注定是成为医生,性格孤僻,ENFP的,一切都是你自己的选择。你自由地选择自己成为什么并且为此承担全部的责任。『一个人不多不少就是他的一系列行径;他是构成这些行径的总和、组织、和一套关系』。而这一系列行径的总和、组织、和一套关系,不是说在你出生之前,在你存在之前就已经确定的,而是你出生之后不断选择的结果。可以这么说,人,是人所有选择的总和。

面向对象是本质先于存在的。

所有的类,接口都被程序员这个『上帝』清晰明确地规定好属性,分配好职责,定义好使命。一个 Student 类,它只能一直履行 Student 所定义的全部职责,在它的整个生命周期里面都无法改变。它无法成为 Teacher,也无法成为 Father。

而函数式编程是存在先于本质的。

没有类,没有接口,没有什么一开始就被定义,之后注定只能扮演某种角色。数据在函数之中流动,生成,毁灭,自由地编织成为一张程序的大网。这张程序的大网,不是由一个个的对象组成,而是一系列事件(函数)的总和。

如果说,人是所有选择的总和,那么面向对象就是所有对象的总和,函数式编程,就是所有函数的总和。

3

函数式编程的思想不仅在哲学上是先进的(相对于漫长的西方哲学史,存在主义在二十世纪才被提出来),在科学上,也符合最新的认知。

《时间的秩序》这本书是意大利理论物理学家卡洛·罗韦利的最新科普作品。它里面介绍了当今理论物理学界对时间和我们生活的这个世界的普遍共识。

首先,时间不是统一的。已经有仪器可以测出来,时间的流逝在山上要比在海平面快。而物体会自然倾向于向时间流逝更慢的地方运动,这就是下落的原因,是引力的来源。所以物理学家从不描述事物『在时间中』如何演化,而是描述事物在它们自己的时间中如何演化,以及时间相对于彼此怎样演化。

时间也是没有方向的。人类感觉上的时间的方向,就是我们通常所说的过去和未来,没有本质上的区别。只是人类模糊的视野下的幻象罢了。

定义清晰的『当下』也是不存在的。『此时此刻』只是人类的幻觉,是人类根据自身经验做出的不合理的推断。『这就像彩虹触碰到森林的那处交界点。我们认为可以看到它,但走过去寻找时,它却不在那儿。』

时间也不会独立存在。它与空间几何以一种复杂的形式交织在一起,构成了爱因斯坦口中的引力场,这种引力场确实可以算是一种实体,真实存在,但又不是完全独立于其他事物。

时间也是不连续的。存在一个最小的时间段,『普朗克时间』,在此之下,时间的概念不复存在。

由于时间的统一性,方向性,当下性,独立性和连续性不复存在,在现代理论物理的基本方程之中,『时间』消失了。

时间的消失并不意味着一切都静止不动。『恰恰相反,这意味着变化普遍存在,无需被时间国王指挥。』于是,科学家们得出了一个结论:世界并不是物体的集合,而是事件的集合。

为什么这么说呢?因为物体是需要在时间中持续存在的,物体状态的改变,维持,依赖了时间的统一性,方向性和连续性。如果这些特性都不存在的话,那么物体也就不存在。而事件是不依赖时间的。『一个吻』是一个事件,你不能说这个吻状态如何,明天怎样,它转瞬即逝,但确实发生。一个『学生』是一系列事件的集合,包括上学,放学,听课,考试等等,没有这些事件的发生,学生也就不是学生。

没有物体存在,只是事件发生。这是理论物理,也是函数式编程。

物体存在,是面向对象的思想。在面向对象的世界里面,一切皆为对象,状态明确,职责分明。但我们知道,在『时间消失』之后,这种存在成为了不可能。

而事件发生,则是函数式的内核,不依赖时间,让事件发生,转换,消亡。没有什么是永恒的状态,也没有什么能够被改变。一切都是转瞬即逝的事件的排列组合。

4

关于函数式编程,存在主义,和理论物理之间的关系,我就暂时介绍到这里,如果你对这三个方面有更多的兴趣的话,可以自行深入研究。我也会给出本文的参考资料。

至此,《编程范式与西方哲学史》这一系列已经完结。这个系列可能是一个过于沉迷自我表达的系列,注定阅读量不会太高。毕竟,编程已经够抽象了,你还要给我讲哲学?但我还是坚持写了下来,梁文道说过,不要瞧不起自己的读者跟受众。我相信会有人跟我一样,喜欢编程,又同时对一切都充满好奇心,包括哲学。希望我的这个系列能够让这些同学对编程范式和西方哲学都有更深的了解。


参考资料

  • 《架构整洁之道》  Robert C. Martin

  • 《时间的秩序》 Carlo Rovelli

  • 《存在主义是一种人道主义》  让-保罗·萨特

  • 《西方哲学史》 中国人民大学公开课  张志伟

  • 《西方哲学十五讲》 张志伟

  • 《西方哲学史:

    从古希腊到当下》 奎纳尔·希尔贝克  尼尔斯·古列尔

《编程范式与西方哲学史》系列的另外两篇