Common Lisp

维基百科,自由的百科全书
跳转至: 导航搜索
Common Lisp
编程范型 多重编程范式
发行时间 1984, 1994 for ANSI Common Lisp
型態系統 动态类型强类型
啟發語言 Lisp, Lisp Machine Lisp, MacLisp, Scheme, InterLisp
影響語言 Clojure, Dylan, Emacs Lisp, EuLisp, ISLISP, R, SKILL, SubL, Scheme
作業系統 跨平台
許可證 GNU通用公共许可证Artistic License
網站 http://common-lisp.net

Common Lisp,缩写为CL(不要和缩写同为CL的組合邏輯混淆),是Lisp的众多方言之一,标准由ANSI X3.226-1994定义。它是为了标准化此前众多的Lisp分支而开发的,它本身并不是一个具体的实现而是各个Lisp实现所遵循的规范。

相对于各种嵌入在特定产品中的语言Emacs LispAutoLISP,Common Lisp是一个通用用途的编程语言。不像很多早期的Lisp,Common Lisp同Scheme一样,其中的变量是有作用域的。

Common Lisp是一个多重范式编程语言,这表现在:

  • 支持各种编程技术:过程编程函数编程面向对象的编程。
  • 动态数据类型,但是可以使用可选的类型声明来提高效率和增强安全性。
  • 可以通过一些标准特性来扩展,例如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关键词符号的值就是它本身,而符号TNIL则一般被分别用于表示布尔真与布尔假。

数据结构[编辑]

Common Lisp中的序列类型包括列表、向量、位向量以及字符串。有很多可以对任意的序列类型起作用的操作符。

就像在几乎所有其它的Lisp方言中一样,Common Lisp中的列表由点对组成,有时候把点对叫做点对单元序偶。一个点对是一种带有两个存储槽的数据结构,两个槽分别叫做它的carcdr。一个列表就是一条点对的链表。每一个点对的car引用一个列表的成员(可能是另一个列表)。而除了最后一个的cdr引用到值nil之外,其余的每一个点对的cdr都引用下一个cons。点对也可以很容易地用于实现树或者其它复杂的数据结构;尽管一般建议使用结构体或者类的实例来代替它们。利用点对还可以创建环形数据结构。

Common Lisp支持多维数组,并且如果有必要可以动态地调整数组的大小。多维数组可以用于数学中的矩阵运算。向量是一维数组。数组可以携带任何类型的成员(甚至在同一个数组中混合不同类型)或指定为包含指定类型的成员,例如整数构成的向量。许多Lisp实现可以在使用指定类型的数组时对数组函数进行优化。有两种指定类型的数组是标准所包含的:字符串和位向量。字符串是由字符构成的向量,而位向量是由比特构成的向量。

哈希表存储数据对象之间的关联。任何值都可以用作哈希表的键或者值。哈希表和数组一样,可以根据需要自动调整大小。

是符号的集合,主要用来将程序根据命名空间分成许多部分。一个包可能会导出一些符号,使这些符号成为公共接口的一部分。一个包可以使用其它的包。

Common Lisp中的结构体和C当中的结构体以及Pascal中的记录类似,表示带有任意数量和类型的字段(也叫做存储槽)的任何复杂的数据结构。Common Lisp中的结构体允许进行单一继承。

和结构体类似,但是提供了更多的特性并且可以进行多重继承。类在后期才被整合进Common Lisp中并且和结构体存在一些概念上的重合。根据类所创建的对象叫做实例。一个特例是广义函数。广义函数既是函数又是实例。

函数[编辑]

在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的符号被认为是如下之一:

  1. 一种特殊操作符(容易根据一个确定的列表检查)
  2. 一个宏(macro)操作符(必须事先被定义)
  3. 函数名(默认),它可以是一个符号或者是一个以符号lambda开始的子式(sub-form)。

如果F是函数名,那么参数A1,A2,...,An被从左到右依次求值,然后找到函数定义,并把这些值作为参数调用这个函数。

定义函数[编辑]

defun用来定义函数。 函数定义给出了函数名,参数名和函数体:

(defun square(x)
   (* x x))

函数定义中可以包括“声明”,它可以指示编译器优化设置或参数的数据类型等。还可以在函数定义中包括“文档字符串”(docstring),Lisp系统用它们形成交互式文档:

(defun square(x)
   (declare (number x) (optimize (speed 3) (debug 0) (safety 1)))
   "Calculates the square of the number x."
   (* 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. GabrielKent Pitman 1998年的一篇论文,其中广泛的比较了这两种方法。[1]

其他类型[编辑]

哈希表是Common Lisp提供的用于存储“键值对”的数据类型。在哈希表中,任何的对象都可以作为键或者值。哈希表在必要的时候会自动调整大小。

[编辑]

Common Lisp中的宏是独一无二的,和C语言中的宏的机制相同,但是在宏扩展的过程中由于可以使用所有现有的Common Lisp功能,因此宏的功能就不再仅限于C语言中简单的文本替换,而是更高级的代码生成功能。宏的使用形式和函数一致,但是宏的参数在传递时不进行求值,而是以字面形式传递给宏的参数。宏的参数一旦传递完毕,就进行展开。展开宏的过程将一直进行到这段代码中的所有宏都展开完毕为止。宏完全展开完毕后,就和当初直接手写在此处的代码没有区别,也就是嵌入了这段代码上下文中,然后Lisp系统就对完整的代码上下文进行求值。

变量捕捉和覆盖[编辑]

因为Common Lisp的宏在展开完毕后就完全嵌入了所处的代码上下文中,相当于以字面形式书写同样的代码,因此在宏展开代码中与上下文代码中相同的符号就会覆盖上面的引用,称为变量捕捉

同其他Lisp的比较[编辑]

实现[编辑]

Common Lisp是由一份技术规范定义而不是被某一种具体实现定义(前者的例子有Ada语言C语言,后者有Perl语言)。存在很多种实现,语言标准详细阐明了可能导致合理歧义的内容。

另外,各种实现试图引入库包来提供标准没有提及的功能。可移植的自由软件库提供了各种特性,Common-Lisp.netCommon Lisp Open Code Collection项目。

Common Lisp设计为由增量编译器实现。优化编译的标准声明(例如内联函数)已进入语言规范的计划。大多数Lisp实现将函数编译成原生的机器语言。其他的编译器编译为中间码,有损速度但是容易实现二进制代码的可移植。由于Lisp提供了交互式的提示符以及函数增量式的依次编译,很多人误会为Lisp是纯解释语言。

一些基于Unix的实现,例如CLISP,可以作为脚本解释器使用;因此,系统可以像调用Perl或者Unix shell解释器一样透明地调用它。

实现的列表[编辑]

免费的可重发布实现包括:

  • CMUCL,最初来自卡内基梅隆大学,现在作为自由软件由一个志愿者团队维护。CMUCL使用一个快速的原生代码编译器。它运行于x86上的LinuxBSD;Alpha上的Linux;以及SolarisIRIXHP-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的大部分子集。
  • Clozure CL(CCL),可以运行在Mac OS,Linux,FreeBSD,Solaris,以及Windows XP等操作系统上,并且支持x86,PowerPC,ARM等硬件平台。

商业实现在这里Franz, Inc.Xanalys Corp.Digitool, Inc.Corman TechnologiesScieneer Pty Ltd.

应用[编辑]

Common Lisp被用于很多成功的商业应用中,最著名的(毫无疑问要归功于Paul Graham的推广)要数Yahoo!商店的站点。其他值得一提的例子有:

  • Orbitz,以飞机票预订为主的站点
  • MiraiIzware 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写成,例如:

同样,Common Lisp也被许多政府和非盈利组织采用。NASA中的例子有:

外部链接[编辑]