Common Lisp
Common Lisp,缩写为 CL(不要和缩写同为CL的組合邏輯混淆),是Lisp的众多方言之一,标准由ANSI X3.226-1994定义。它是为了标准化此前众多的Lisp分支而开发的,它本身并不是一个具体的实现而是各个Lisp实现所遵循的规范。
相对于各种嵌入在特定产品中的语言Emacs Lisp 和 AutoLISP,Common Lisp 是一个通用用途的编程语言。不像很多早期的Lisp,Common Lisp同Scheme一样,其中的变量是有作用域的。
- 支持各种编程技术:过程编程,函数编程 和 面向对象的编程。
- 动态数据类型,但是可以使用可选的类型声明来提高效率和增强安全性。
- 可以通过一些标准特性来扩展,例如 Lisp宏(程序自我进行的编译时代码重排 (compile-time code rearrangement accomplished by the program itself))和 阅读器宏(赋予用户自定义的保留字以特殊意义的符号扩展 (extension of syntax to give special meaning to characters reserved for users for this purpose))。
语法
Common Lisp 是一种 Lisp; 它使用 S-表达式 来表示代码和数据结构。 函数和宏调用以列表的形式写出,列表的第一项是函数名,就像在这些例子中:
(+ 2 2) ; 将 2 加上 2, 得 4
(setf p 3.1415) ; 设定变量 "p" 等于 3.1415,"pi" 是一个内置变量,不能用setf设置它
(defun square (x) (* x x)) ; 定义一个函数用来计算一个数的平方:
; 执行这个函数:
(square 3) ; 返回 "9"
数据类型
Common Lisp 拥有相当丰富的数据类型,比很多语言都要多。
标量类型
数字 类型包括整数,分数,浮点数,和复数。Common Lisp 使用 bignum 来表示任意长度和精度的数值。分数类型精确地表示分数,这是很多语言都不具备的能力。 Common Lisp 自动将数值转换成适当的类型。
Common Lisp 字符 类型并不仅仅是 ASCII 字符,这是因为 Lisp 在 ASCII 出现前就存在了。 一些现代的实现允许使用Unicode字符。
符号(Symbol)类型是Lisp语言共有的,而在其它语言中就较少见。一个符号是一个唯一的命名数据对象。与其它语言中的标识符(Identifier)类似,Lisp中的符号可以用作变量名,但它们也是可以独立使用的一种数据对象。一般来说,对一个符号求值时会得到以该符号为名的变量的值,但也有例外:形如:foo的关键词符号的值就是它本身,而符号T和NIL则一般被分别用于表示布尔真与布尔假。
数据结构
Common Lisp 的序列类型包括表(lists),向量(vectors), 位向量(bit-vectors),和字符串(strings)。
同任何其他的Lisp一样,Common Lisp中的列表称作conses,有时候叫做cons cells 或者 pairs。一个cons就是拥有两个槽的数据结构,这两个槽被称作 car 和cdr。
函数
在 Common Lisp 里, 函数 是一种数据类型。 例如,可以写出以一个函数作为参数的函数,同时函数的返回值也可以是函数。这就让用函数描述非常通用的操作成为可能。
以至少一个函数作为输入、或者返回函数的函数称为高阶函数。Common Lisp 的库很强的依赖这种高阶函数。 例如,sort(排序)函数用一个 比较操作符 作为他的参数之一。这样一来,这个函数就不但可以用来对任何类型的数据排序,还可以根据一个关键码对数据结构排序。
(sort (list 5 2 6 3 1 4) #'>)
; Sorts the list using the > function as the comparison operator.
; Returns (6 5 4 3 2 1).
(sort (list '(9 a) '(3 b) '(4 c)) #'< :key #'first)
; Sorts the list according to the first element of each sub-list.
; Returns ((3 b) (4 c) (9 a)).
这一求值模型对于函数很简单。当求值器遇到一式形如 (F A1 A2...)
,那么名为 F 的符号被认为是如下之一:
- 一种特殊操作符(容易根据一个确定的列表检查)
- 一个宏(macro)操作符(必须事先被定义)
- 函数名(默认),它可以是一个符号或者是一个以符号
lambda
开始的子式(sub-form)。
如果 F 是函数名,那么参数 A1, A2,...,An 被从左到右依次求值,然后找到函数定义,并把这些值作为参数调用这个函数。
定义函数
宏 defun
用来定义函数。
函数定义给出了函数名,参数名和函数体:
(defun square (x)
(* x x))
函数定义中可以包括 “声明”,它可以指示编译器优化设置或参数的数据类型等。还可以在函数定义中包括“文档字符串”(docstring),Lisp 系统用它们形成交互式文档:
(defun square (x)
<EM>(declare (number x) (optimize (speed 3) (debug 0) (safety 1)))
"Calculates the square of the number x."</EM>
(* x x))
匿名函数用 lambda
表达式定义。Lisp 编程频繁使用高阶函数,以匿名函数作为其参数的作法十分有效。
还有一些有关于函数定义和函数操作的运算符。如,操作符 compile
可以用来重新编译函数。(一些Lisp系统默认下在解释器里运行函数,除非指示编译它;其他Lisp系统在函数输入时即被编译。)
函数名字空间
函数的名字空间与数据变量的名字空间是分离的。这是 Common Lisp 和Scheme编程语言的一个重要不同之处。 在函数名字空间定义名字的操作符包括 defun
,flet
,和 labels
。
要用函数名把函数作为参数传给另一个函数,必须使用function
特殊操作符,通常简略为 #'。上文第一个 sort
的例子中,为了引用在函数名字空间名为 >
的函数,使用了代码 #'>
。
Scheme编程语言 的求值模型更简单些:因为只有一个名字空间,式(form)中所有位置都被求值(以任意顺序)-- 不仅是参数。 所以以一种方言 (dialect) 写就的代码往往令熟悉其它方言程序员感到迷惑。例如,许多 CL 程序员喜欢使用描述性的变量名如 "list" 或 "string",在 Scheme 中这将导致问题,因为它们可能局部覆盖了函数名字。
为函数提供分离的名字空间是否有益是 Lisp 社区不断争论的主题之一,常被称为 “Lisp-1 与 Lisp-2 辩论”。这些名称出现于Richard P. Gabriel 和 Kent Pitman 1998 年的一片论文,其中广泛的比较了这两种方法。 [1]
其他类型
哈希表是Common Lisp提供的用于存储“键值对”的数据类型。在哈希表中,任何的对象都可以作为键或者值。哈希表在必要的时候会自动调整大小。
宏
Common Lisp中的宏是独一无二的,和C语言中的宏的机制相同,但是在宏扩展的过程中由于可以使用所有现有的Common Lisp功能,因此宏的功能就不再仅限于C语言中简单的文本替换,而是更高级的代码生成功能。宏的使用形式和函数一致,但是宏的参数在传递时不进行求值,而是以字面形式传递给宏的参数。宏的参数一旦传递完毕,就进行展开。展开宏的过程将一直进行到这段代码中的所有宏都展开完毕为止。宏完全展开完毕后,就和当初直接手写在此处的代码没有区别,也就是嵌入了这段代码上下文中,然后Lisp系统就对完整的代码上下文进行求值。
Variable capture and shadowing
因为Common Lisp的宏在展开完毕后就完全嵌入了所处的代码上下文中,相当于以字面形式书写同样的代码,因此在宏展开代码中与上下文代码中相同的符号就会覆盖上面的引用,称为变量捕捉。
同其他Lisp的比较
实现
Common Lisp 是由一份技术规范定义而不是被某一种具体实现定义(前者的例子有Ada语言和C语言,后者有Perl语言)。 存在很多种实现,语言标准详细阐明了可能导致合理歧义的内容。
另外,各种实现试图引入库包来提供标准没有提及的功能。可移植的自由软件库提供了各种特性,Common-Lisp.net 和 Common Lisp Open Code Collection 项目。
Common Lisp 设计为由增量编译器实现。 优化编译的标准声明(例如内联函数)已进入语言规范的计划。 大多数Lisp实现将函数编译成原生的机器语言。其他的编译器编译为比特码,有损速度但是容易实现二进制代码的可移植。由于Lisp提供了交互式的提示符以及函数增量式的依次编译,很多人误会为Lisp是纯解释语言。
一些基于Unix的实现,例如CLISP,可以作为脚本解释器使用;因此,系统可以像调用Perl 或者Unix shell解释器一样透明的调用它。
实现的列表
免费的可重发布实现包括:
- CMUCL,最初来自卡内基梅隆大学,现在作为自由软件由一个志愿者团队维护。 CMUCL 使用一个快速的原生代码编译器。它运行于 x86上的Linux和BSD;Alpha上的Linux;以及 Solaris、 IRIX 和 HP-UX 。参见 [2]
- GNU CLISP,是一个bytecode编译的实现。它可移植并运行在很多Unix和Unix风格的系统上(包括Mac OS X), 以及Microsoft Windows 和一些其他系统。
- Steel Bank Common Lisp (SBCL),是 CMUCL 的一个分支。 "宽泛的说,SBCL 是CMUCL的可维护性加强版本。" [3] SBCL 运行的平台和 CMUCL 一样,除了 HP/UX;另外,它运行于PowerPC上的Linux,SPARC,MIPS,和Mac OS X之上。 SBCL 不使用解释器;所有的语句编译为原生机器码。
- GNU Common Lisp (GCL), GNU项目的 Lisp 编译器。GCL还不是完全兼容ANSI,但它仍然是一些大型项目所选择的实现,包括数学工具 Maxima, AXIOM 和 ACL2。GCL 运行在 十一种架构的GNU/Linux 下,以及 Windows, Solaris, 和 FreeBSD。
- Embeddable Common Lisp (ECL),设计为可嵌入C语言应用中;
- OpenMCL,Macintosh Common Lisp的开源分支。如同名字所示,OpenMCL is native to the Macintosh;运行于Mac OS X,Darwin,和PowerPC 上的 Linux 。
- Movitz 实现了x86上的Lisp环境而不依赖任何OS。
- Armed Bear Common Lisp 是一个运行在Java虚拟机上的Common Lisp实现。它包括了一个编译器可以编译Javabyte code,并允许Common Lisp调用Java库。Armed Bear Common Lisp 是Armed Bear J Editor的一个组件,但它也能独立使用。
- Jatha 是一个Java库,实现了Common Lisp的大部分子集。
商业实现在这里Franz, Inc.,Xanalys Corp.,Digitool, Inc.,Corman Technologies and Scieneer Pty Ltd.。
应用
Common Lisp 被用于很多成功的商业应用中,最著名的(毫无疑问要归功于Paul Graham的推广)要数Yahoo! 商店的站点。其他值得一提的例子有:
- Orbitz,以飞机票预订为主的站点
- Mirai,Izware LLC's fully integrated 2d/3d computer graphics content creation suite that features what is almost universally regarded as the best polygonal modeler in the industry, an advanced IK/FK and non-linear animation system (later popularized by such products as Sega's Animanium and Softimage XSI, respectively), and advanced 2d and 3d painting. It is used in major motion pictures(most famously in New Line Cinema's Lord of the Rings), video games and military simulations.
- Piano,一个用Lisp写的商业的航空期前期设计包以及与它的竞争对手的比较
- Xanalys Corp.的调查软件,被全球的警察,安全部门和防止诈骗服务部门采用
- Genworks International的多用途说明语言(GDL),是一个基于CL的开发工具,用来创建基于web的工程,设计和商业应用
也有很多成功的开源应用用Common Lisp写成,例如:
- Applicative Common Lisp,a full-featured theorem prover for a subset of Common Lisp.
- Maxima,a sophisticated computer algebra system。
- Compo,a language allowing complex musical structures to be described in a natural way.
- Lisa,a production-rule system to build "intelligent" software agents.
同样,Common Lisp也被许多政府和非盈利组织采用。NASA中的例子有:
- SPIKE,the Hubble Space Telescope planning and scheduling system.
- Remote Agent,winner of the 1999 NASA Software of the Year Award.
外部链接
- The Common Lisp HyperSpec,Common Lisp标准的电子版本
- The CLiki, 关于Unix风格系统下的Common Lisp的Wiki
- Lisp用户协会
- Common Lisp快速入门
- Common Lisp the Language, 2nd Edition, 也被称为 "CLtL2". Guy Steele's book on Common Lisp,介绍了ANSI Common Lisp标准的基础知识
- The Common Lisp Cookbook,有用的编程方法收集。
- Paul Graham的页面 关于Lisp。如果你跟随链接,你会找到他的电子书On Lisp,这本书专注于Common Lisp中的宏设计。
- Common Lisp:符号计算的渐进入门 by David S. Touretzky,有电子版本并为新手而写。
- Peter Norvig's page 包含了很多有趣的Common Lisp资源。
- Practical Common Lisp 同名的电子书。已进入了2006 Jolt大奖的Finalist。
- Casting Spells in Lisp Common Lisp的卡通化介绍。
- Igor Engraver:一流的音乐标记法和用Common Lisp写成的程序。