译文

原文参考Relationship between OO and functional programming?, 以下是译文。

第 1 个阶段

第 1 个阶段是 50 年前我在(ARPA)研究生院的第一周,我的数学、分子生物学、系统和编程等背景与 Sketchpad、Simula 和拟议中的 ARPAnet 发生冲撞,无法协调。这导致了这样一种见解(几乎是同义反复): 可以把一台真实计算机无限地划分为彼此通信的虚拟计算机,如此一来,(在虚拟计算机上)将:

  1. 保留全部的表达能力
  2. 能够对任何可以建模的东西进行建模
  3. 能够大规模扩展现有方法来拆分计算机

我喜欢这个想法。时间共享的 “进程”已经是这种虚拟机的表现形式,但由于它们的开销,它们缺乏普遍实用性(所以要想办法把开销去掉……)。

虽然你可以对任何东西建模(包括数据结构),但这对我来说根本不是重点(它将让你回到了汤(soup)里(译者注:原始材料/环境))。最重要的是封装和消息传递,以提供松散的耦合,这将在极端的扩展下工作(让人想起生物学和生态学的方式)。

第 2 个阶段

第 2 个阶段是将 :

  • Lisp 本身的 “Lisp 世界”
  • McCarthy 关于机器人和时间逻辑(Temporal Logic)的想法
  • ARPA 内部(尤其是麻省理工学院)正在进行的 AI 工作(尤其是 Carl Hewitt 的 PLANNER 语言)

结合在一起。其中一个想法是,对象可以对外提供服务,并且面向目标(使用 PLANNER 风格的接口语言)。

第 3 个阶段

第三个阶段是在 Parc 实施一系列的 Smalltalks,试图在未来必然需要的东西,和 Parc 的 Alto 计算机(128K 字节的内存,其中一半用于显示!)可以做的事情之间找到一个平衡。这是通过与 Dan Ingalls 以及其他富有才华的伙伴一同完成的。虽未完全抵达理想,但还算不赖。

第 4 个阶段

第 4 个阶段(在 Parc)重新认真地审视时间逻辑(Temporal Logic)和 “世界线”(world-line)的想法(下文会有详细介绍)。

第 5 个阶段

第 5 个阶段是再次认真思考扩展的问题,并将 诸如 Gelernter 的 Linda “协调语言” 作为一种方法,通过描述匹配,以一般的发布和描述的方式做松散耦合。我目前还是很喜欢这个想法,并期待看到它能发展到让对象之间可以真地”协商意义”。


麦卡锡的时间逻辑(Temporal Logic): “时间中的真函数”

对过去的历史背景(context)有所了解,将有助于理解这儿提出的观点。让我们展开论述,也试着提供一些参考文献。

我对这一切的思考要追溯到 50 年代末的 John McCarthy。John 是一位优秀的数学家和逻辑学家。他希望自己能够进行一致的推理–而且希望他的程序和机器人也能做到这一点。机器人是一个关键,因为他希望机器人在某个时间在费城,另一个时间则在纽约。在普通的逻辑中,这是个问题。但 John 通过给所有的 “事实”(facts)添加一个额外的参数来解决这个问题,这个参数代表了一个事实为真时的 “时间帧”(time frame)。这创造了一个简单的时间逻辑,将 “事实集合”可视化为世界线(world-line)的堆叠”层”。

这很容易被推广到 “变量”、”数据”、”对象”等世界线。从个体的角度看,”值” 被值的 “历史”(译者注: 可以视为版本)所代替,从系统的角度看,整个系统在每一次系统处于计算之间的时候,都用它的稳定状态来表示。Simula 后来实现了这个想法,虽然较弱,但很有用。 (译者注: Daniel Ingalls 在 Lively 中实现的 undo 和 action-log(在对象级别)操作可能于此有关, 此外,Croquet 也关注这个概念)

我还应该提到 Christopher Strachey(Lisp 和 McCarthy 的忠实粉丝),他意识到多种编程可以被统一,并且通过总是使用 “旧”值(来自于前一帧(frame))来制造”新”值,并将其安置在新的帧(frame)中,从而使其更加安全。他通过观察 Lisp 中的 “尾递归 “是何等干净,看出它可以被写成一种涉及看似赋值语句的循环: 赋值语句的右侧从时间 t 取值,被赋值的变量(左侧)在时间 t+1 中存在(而且只能进行一次这样的赋值)。如此一来,通过模拟时间和状态,统一了函数式编程和 “类似命令式”(imperative like)的编程。

顺便提一下 Ashcroft 和 Wadge 的编程语言 Lucid,它扩展了 Strachey 的许多思想…………。

同样值得关注的是数据库上的 “原子事务”(atomic transactions),这是一个与 “粗颗粒” 非常相似的想法。没有什么东西会被粉碎,相反,事情被组织起来,这样新的版本是以一种非破坏性的方式创建的,没有竞争条件。这种系统里存在着 由不同版本的事实构成的历史。

这里的关键概念是 “时间是个好主意” – 我们想要它,我们想要以安全合理的方式处理它 – 这些方式大多(甚至全部)可以由纯函数将其在稳定的世界线(world-line)状态序列之间进行转换。

刚计算出来的稳定状态是非常有用的。它永远不会再被改变–所以它代表了系统模拟的一个”版本” – 它可以安全地用作原始值,之后函数将其转置到下一个稳定状态(值)。它也可以作为创建系统在当前时刻的截面的可视化的来源。历史记录可以用于调试、撤销、回滚等。

在这个模型中(部分来自 McCarthy、Strachey、Simula 等),”稳定状态之间不存在时间”: “时钟”只有在每个新状态完成时才会前进。就程序而言,CPU 本身并不充当时钟。(译者注,croquet 中采用“伪时间”的概念)

这就产生了一种非常简单的构建确定性关系的方法,它有一个内在的、干净的时间模型。

由于各种令人遗憾的原因,这种想法(关注安全)在 60 年代失传了,人们转而在命令式编程中允许竞争条件,然后试图使用可怕的信号符(semaphores)等来保护它们,这可能导致锁定。

我已经提到了一些我对对象的一系列想法。在某些时候,任何对对象之间的消息传递感兴趣的人,如果知道 Lisp,就会被吸引到 “apply”,并注意到一种对象(一个 lambda “东西”(thing),它可能是一个闭包)被绑定到参数上(这有点像消息)。如果意识到 Lisp 1.5 是如何实现晚绑定参数求值(evaluation)的可能性(采用 FEXPRs 而不是 EXPRs)– 未求值的表达式可以作为参数传递,并在之后进行求值,这就更深刻了。这使得那些不雅的 “特殊形式”(如条件)可以被省去,它们可以被写成一种普通的惰性函数(lazy function)。

通过上面提到的时间建模,可以松开 “eval-apply”之间耦合的”齿轮”,通过安全的消息传递得到时间层之间的函数关系。

因为我一向喜欢用 “模拟的视角” 来看待计算,所以我认为 “对象”和 “函数” 是相辅相成的思想,彼此之间并不冲突。(我还有许多其他的动机,包括一直在思考的,从认识论上来说,对于儿童来说,好的语言应该是什么……但这是另一个故事)。

参考