1983年爱丁堡的整合提案
Standard ML,简称SML,是1980年代研究者在既有ML实现基础上共同设计的通用编程语言。早期ML服务于机器辅助证明,后来不同实现又发展出各自的数据类型、语法和编译工具。罗宾·米尔纳希望整理这些经验,使程序员和实现者有一套较稳定的共同语言可用。
1983年4月,米尔纳在爱丁堡提出以“Standard ML”为名的手写方案,一批研究者在他家中讨论了三天。参与者包括罗德·伯斯托尔、卢卡·卡尔代利、戴维·麦奎因以及来自剑桥等地的同事。6月的第二稿吸收讨论和通信意见,11月又形成打字稿。这里的“Standard”表示统一方言的设计意图,并非当时已有标准化机构颁布的正式标准。
核心语言与大型程序的两层问题
初期设计保留ML的静态类型推断和函数式编程能力,同时吸收代数数据类型、模式匹配以及按不同情况定义函数的方法。程序可以清楚表达一个值有哪些构造形式,再对这些形式分别处理。语言也保留状态更新与异常机制,因此不局限于没有副作用的数学函数。
当程序扩大后,单个表达式的类型正确还不够,多个组件怎样组合也成为问题。1984年和1985年的爱丁堡会议继续讨论核心语言与模块。麦奎因把此前研究的模块思想发展为结构、签名和函子,使类型、函数和异常可以作为成组的接口组织起来。
用栈解释结构与接口
麦奎因收录在1986年报告中的模块说明,以栈给出具体例子。一个结构把栈的数据类型、判断空栈的函数、取栈顶和弹出操作放在一起。把元素依次压入栈后,取栈顶会返回最近压入的元素;弹出则得到剩余的栈。对空栈进行这些操作时,例子使用异常报告失败。
结构提供具体实现,签名描述其中对外可用的名称及其类型。使用者依据接口调用操作,实现者则可以通过适当的抽象接口控制数据表示的可见范围。函子进一步把一个或多个结构作为参数,产生新的结构,使同一组程序组织方法能够用于不同的类型和操作组合。
例如,把“元素类型及其比较操作”作为参数,便可以围绕这份接口组织可复用的有序数据组件。关键在于组件接收的操作与类型相符,而不是把所有元素都强行改成某一种内置类型。这种参数化把ML在函数层次上的复用思想扩展到较大的程序单元。
实现与设计同步推进
约在1984年,凯文·米切尔、艾伦·迈克罗夫特和约翰·斯科特在爱丁堡实现了Standard ML核心语言。1985至1986年的模块原型中,米切尔负责求值,罗伯特·哈珀处理签名检查。这些实现提供了检验设计的场所,也让模块类型检查中的困难具体显现出来。
与此同时,戴维·马修斯发展Poly/ML实现。1986年起,贝尔实验室的麦奎因与普林斯顿大学的安德鲁·阿佩尔开始Standard ML of New Jersey项目。多个编译器不是同一产品的连续版本,而是围绕共同语言发展的不同实现,分别探索运行系统、代码生成和模块处理。
参考:[3]
把语言含义写成共同规则
哈珀、米尔纳和马兹·托夫特等人从1985年前后推进形式语义工作。1990年出版的《Standard ML定义》把语法、静态语义和动态语义分开:语法说明程序的构成,静态语义处理名字、类型和模块接口,动态语义说明求值时产生什么结果。
这使语言的含义不必只依赖某个编译器的行为。实现者可以按规则检查程序是否符合类型和接口约束,也可以比较不同实现对同一构造的解释。设计讨论与实现经验不断影响这些规则,模块共享、参数匹配等问题因而经历了多轮细化。
1997年修订及其用途
1997年修订版由米尔纳、托夫特、哈珀和麦奎因共同署名。它根据早期实现与使用经验调整类型纪律和模块规则,包括采用值限制约束多态,整理类型共享,并加入不透明签名匹配等机制。修订沿用核心语言与模块语言的分层,同时简化已暴露问题的部分。
Standard ML随后用于语言实现、教学和研究系统。它的突出成果既是一种可编程的工具,也是一种把语言设计、编译器实践与形式定义相互校验的工作方式。1983年的整合提案、1980年代的实现与模块讨论、1990年的定义出版和1997年修订,构成彼此衔接的不同阶段。