由信息系统工作的难题出发

Clojure由程序员里奇·希基设计,2005年开始开发,2007年秋以开源项目形式公开。希基此前使用C++、Java和C#制作过排程、广播自动化、收益管理及选举分析等系统。他希望获得一种适合实际工作、又能减少可变状态复杂性的语言,于是用个人积蓄支持休整期中的设计与实现。

它采用Lisp的表达形式和函数式编程方法,但没有把已有Lisp简单搬上新平台。运行于Java虚拟机,是设计本身的重要选择:程序可以直接利用宿主生态的类库,减少进入已有组织和系统的障碍。希基在回顾中把函数式、宿主平台与Lisp三者的结合视为这门语言的位置。

参考:[1]

2007年公开试用,2009年推出1.0

希基在语言史论文中把2007年10月17日列为向jFli邮件列表宣布Clojure可用的日子。当时它仍是alpha版本,发布者邀请愿意试用的人提供反馈;公开亮相与稳定的1.0发行并不是同一件事。

2009年5月4日,希基正式宣布Clojure 1.0。他说明,编号版本让用户可以依赖稳定的应用程序接口,随后只接受修复错误的增量更新,也方便类库针对明确版本开发。公告感谢社区在此前约十八个月提供的想法、测试、工具、文档和补丁,并把一些新功能留给1.1。这种安排将早期持续试验转成较可预测的使用节奏。

参考:[1] [2]

保留旧值,再生成新值

Clojure的集合以不可变和持久化为核心。不可变表示一个值建立后不会被原地改写;持久化在这里表示生成更新后的集合时仍保留旧集合可用,并不等于把数据写入磁盘。实现通过共享未改变的内部结构,避免每次操作都把全部内容重新复制。

例如,表达式(conj [1 2] 3)会产生向量[1 2 3],原来的[1 2]仍是原来的值。多个计算可以各自保留自己拿到的版本,程序员不必担心另一处修改了同一集合后,使先前的读取突然失效。向量按连续整数索引访问;映射将键关联到值;这些集合又能通过统一的序列接口交给通用处理函数。

参考:[3]

需要变化时协调多个引用

现实程序仍然需要记录变化。Clojure把某个持续存在的身份与它在某时刻持有的值分开,Ref是其中一种可变引用。Ref所指向的存储位置只能在事务内更新,软件事务内存负责使一组相关修改一起生效,或全部不生效;遇到冲突时,事务可以自动重试。

官方参考文档用一个交换示例说明这种协调:若干Ref各自保存一个向量,多个线程随机选择两个位置,使用dosync包住两次alter操作来交换数字。更新完成时,数字的总体集合不应出现丢失或重复。不可变集合使事务能够低成本地准备新版本,再统一提交;因为程序可能被重试,事务内不宜直接执行写文件等外部副作用。

参考:[4]

交互式计算与编译并存

Clojure程序以表达式为单位求值。普通函数调用把操作符放在括号中的首位,例如(+ 1 2)求得3;列表也可以表示特殊形式或宏,宏先处理尚未求值的程序形式,再把生成的形式交回求值过程。因此,相似的括号外观背后仍需区分普通调用和语言控制结构。

表达式既可在读取、求值、打印循环中逐项试验,也可从文件载入。交互操作并不意味着函数只被解释执行:Clojure会在需要时编译表达式,官方文档明确说明其实现没有另设解释器。程序员由此能在正在运行的环境里逐步构建和检查函数,同时利用Java平台。2007年的公开版本开启了这种工作方式的社区试用,2009年的1.0则为依赖稳定接口的使用者提供了明确起点。

参考:[5] [2]