Common Lisp

语法

Common Lisp是Lisp编程语族的一种方言; 它使用S-表达式来表示源码和数据结构。函数呼叫、宏形式和基本形式都以列表来编写，列表的第一项是函数名称，如以下范例：
 (+ 2 2)   ; 将 2 加上2 得 4。函數名稱為'+'，在Lisp語法中是唯一的(只能作用於數值)。
 (defvar *x*)      ; 先確保*x* 變量存在，尚未賦值給它。星號也是變量名稱的一部份，
                   ; 依慣例約定表示一個特殊（全局）變量。符號 *x* 與生俱有的屬性是
                   ; 對於它後續的綁定是動態可變的，而非詞法靜止不變的。
 (setf *x* 42.1)   ; 對 *x* 變量賦予浮點數值42.1。
 ;; 定义计算一个数的平方函数：
 (defun square (x)
               (* x x))
 ;; 执行这个函数：
 (square 3)        ; 返回平方值9
 ;; 'let'構造為區域變量創建一個作用域。這裡變量'a' 被綁定到6，變量'b'被綁定到4。&nbsp;;; 'let'的內部是一個函式體，對它求值後會返回最後一個計算值。這個'let'表達式將
 ;; a 和 b 相加的結果返回。變量 a 和 b 只存在於詞法作用域中，除非它們已先被標記&nbsp;;; 成特殊變量（例如上述的DEFVAR）。
 (let ((a 6)
       (b 4))
   (+ a b))        ; 返回數值10

资料型别

Common Lisp 拥有丰富的资料型别。

标量型别

数值型别包括整数，分数，浮点数和复数。Common Lisp使用大数（bignums）来表示任意大小和精度的数值。
分数型别确切地代表分数，很多语言并不具备这种能力。Common Lisp会自动将数值转换成适当的型别。有许多方式取舍数值，函数round将参数四舍六入为最接近的整数，逢五则取偶整数。truncate，floor和ceiling分别朝向零，向下或向上取整数。所有这些函数将舍去的小数当作次要值返回。
例如，（floor -2.5）产生 -3, 0.5；（ceiling -2.5）产生 -2，-0.5；（round 2.5）得到 2,0.5；和（round 3.5）得到 4，-0.5。
Common Lisp字元型别不限于ASCII字符，因为在ASCII出现前Lisp就已经存在了。大多数现代实现允许Unicode字元。
符号（Symbol）型别是Lisp语言共有的，而在其它语言中较少见。一个符号是个命名唯一的资料物件，它拥有几个部分：名称，值，函数，属性列表（property list）和套件。其中，值单元和函数单元是最重要的。Lisp中的符号通常类似于其它语言中的标识符（identifier）用法：保存变量的值；然而还有很多种用途。一般来说，对一个符号求值时会得到以该符号为变量名称的值，但也有例外：譬如在关键符套件中的符号，形如:foo的符号值就是它本身（自我评估的，self-evaluating），而符号T和NIL则用于表示布尔逻辑值真与假。Common Lisp可设计容纳符号的命名空间，称为“套件”（package）。

数据结构

Common Lisp的序列型别包括列表、向量、位元向量和字串。有许多函式可对应不同型别的序列进行操作。
CL如同所有Lisp方言，列表由点对（conses）组成，有时称为cons单元、序偶或构对。一个点对是带有两个储存槽的数据结构，分别称为car和cdr。列表就是一条点对的串列，或只是空列表。每一个点对的CAR会参照列表的成员（可能是另一个列表）。而除了最后一个的CDR参照到nil值之外，其余的CDR都会参照下一个点对。Conses也能轻易地实现树和其它复杂的数据结构；尽管一般建议以结构体或是类别的实例来代替。利用点对能够创建循环形的数据结构。
CL支援多维阵列，且如需要能动态地调整阵列大小。多维阵列常用于数学中的矩阵运算。向量就是一维阵列。阵列可载入任何型别（甚至于混合的型别）的成员，或只专用于特定某一型别的成员，例如由整数构成的位元向量。许多Lisp实作会根据特定型别，对阵列的操作函数进行优化。两种特定型别的专用阵列是内建的：字串和位元向量。字串是由许多字元构成的向量，而位元向量是由许多位元构成的向量。
杂凑表储存资料物件之间的关联，任何物件都可以作为杂凑表的键或值。和阵列一样，杂凑表可依需求自动调整其大小。
套件是一组符号的集合，主要用于将程序的个别部分区分命名空间。套件能汇出一些符号，将它们作为共用界面的某一部分，也可以汇入其它套件引用并概括承受其中的符号。
CL的结构体（Structures）类似于C语言的structs和Pascal的records，是一种任由使用者发挥的复杂数据结构定义，表示具有任意数量和任何型别的字段（也叫做槽）。结构允许单一继承。
类别（Class）在后期被整合进Common Lisp中，有些概念与结构体重叠，但类别提供了更多的动态特性和多重继承（见 CLOS）。由类别创建的物件称为实例。有个特殊情况是泛型（Generics）的双重角色，泛型既是函数，也是类别的实例物件。

定义函数

宏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系统在函数输入时即被编译。）

定义泛型函数及方法

defgeneric宏用来定义泛型函数，而defmethod宏则用来定义方法。泛型函数是一些方法的集合。方法可依照CLOS标准类别、系统类别、结构类别或物件，以特定方式处理它们所使用的参数。许多型别都有相对应的系统类别。当呼叫泛型函数时，多样派发（multiple-dispatch）将会依型别确定要应用的有效方法。如下列范例展示了对不同型别的参数如数值、向量或字串，设计对应的add方法将两个物件相加的动作。
 (defgeneric add (a b))
 (defmethod add ((a number) (b number))
    (+ a b))
 (defmethod add ((a vector) (b number))
    (map 'vector (lambda (n) (+ n b)) a))
 (defmethod add ((a vector) (b vector))
    (map 'vector #'+ a b))
(defmethod add ((a string) (b string))
  (concatenate 'string a b) )
 (add 2 3)                   ; returns 5
 (add #(1 2 3 4) 7)          ; returns #(8 9 10 11)
 (add #(1 2 3 4) #(4 3 2 1)) ; returns #(5 5 5 5)
 (add "COMMON " "LISP")      ; returns "COMMON 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年的一篇论文，其中广泛的比较了这两种方法。

作用域

与许多其它编程语言中的程式一样，Common Lisp编程使用名称来引用变量、函数和许多其它类型的实体。被命名的参照只在其作用域中有用。名称与引用实体之间的关联称为绑定。作用域是指确定名称具有特殊绑定的情况。

全局

Lisp中的一些环境总是存在于全局作用域之中， 例如定义了一个新型别，那么以后在任何地方都会知道它。

该类型别的参照会从全局作用域中的环境去寻找。

动态

环境在Common Lisp中有一种类型是动态环境。在这种环境中建立的绑定具有动态的作用域，这表示某些构造例如let，会在执行的起点就先建立绑定，而在该构造完成执行时消失：它的生命周期依附着这区块动态地触发和停用。然而动态绑定不仅在该区块中可见；对于从该区块中调用的所有函数也是可见的。这样的可见性被称为不定的作用域。具有动态（依附区块的触发和停用相关的生命周期）和不定作用域（从该区块调用的所有函数可见）的绑定，被称为具有动态作用域。
Common Lisp支援动态作用域的变量，也称为特殊变量。有些其它类型的绑定也必须是动态作用域的，例如重新启动和捕获标签。函数绑定不能以flet（仅提供词法范围的函数绑定）进行动态作用域，但可以将函数物件（Common Lisp中的第一类物件）分配给动态作用域的变量，在动态作用域内使用let绑定，然后再以funcall或APPLY调用。
动态作用域非常有用，因为它将参照的清晰度和规律添加到全局变量中。计算机科学中的全局变量被认为是潜在的错误来源，因为它们可能导致模组之间存有特殊隐蔽的沟通渠道，从而导致令人惊讶而不在预期中的交互作用。
在Common Lisp中，只有顶层绑定的特殊变量就像其它编程语言中的全局变量一样。它可以储存一个新的值，该值仅替换顶层绑定中的值。造成使用全局变量的核心错误，是粗心的替代了全局变量值。但是，使用特殊变量的另一种方法是，在表达式中给它一个新的区域绑定。这有时被称为“重新绑定”变量。动态作用域中对变量的绑定，会创建一个临时的新内存位置给予该变量，并将该名称与该位置相关联。当该绑定有效，对该变量的所有参照都指向新的绑定；之前的绑定则是被隐藏起来的。当绑定表达式的执行结束时，临时的内存位置消失，而旧绑定浮现出来，变量的原始值依旧完好无损。当然，同一变量的多个动态绑定可以嵌套。
在支援多绪的Common Lisp实作中，动态作用域是针对每个执行绪的。因此，特殊变量是当成执行绪区域存储的抽象化。如果一个执行绪重新绑定了特殊变量，则此重新绑定对其它执行绪中的该变量没有作用。储存在绑定中的值只能由创建该绑定的执行绪取得。如果每个执行绪绑定一些特殊变量*x*，则*x*的行为就像执行绪在本地中储存一样。在没有重新绑定*x*的执行绪中，它的行为就像一个普通的全局变量：所有这些执行绪的参照都会指向*x*的顶层绑定。
动态变量可以用来扩展执行上下文，并附加上下文讯息，这些信息在函数之间隐含地传递，而不必显示为额外的函数参数。当执行控制的转移必须穿过不相关的代码层时，不能借由额外参数来扩展传递附加数据，所以这是非常有用的。这样的情况通常需要一个全局变量，必须能够被储存和恢复，以便在递归时不会中断：动态变量的重新绑定可以处理此情形。该变量必须是执行绪区域的（或必须使用大的互斥, mutex），因此这个情况不会在执行绪下断开：动态作用域的实作也可以处理此情形。
在Common Lisp函式库中有很多标准的特殊变量。例如，所有标准I/O流都储存在顶层为众所熟知的特殊变量的绑定中，即*standard-output*。
假设有个foo函数写入标准输出：
  (defun foo ()
    (format t "Hello, world"))
要撷取其输出中的字串，*standard-output*可以被绑定到一个字串流，并调用它：
  (with-output-to-string (*standard-output*)
    (foo))
 -> "Hello, world" ; gathered output returned as a string

区域

Common Lisp支援词法环境。形式上，词法环境中的绑定具有词法作用域，并可能具有不定的范围或动态的范围，取决于命名空间的类型。词法作用域实际上表示可见性被限制在绑定建立的区块中。参照没有以文本（即词法地）嵌入在该区块中，根本看不到该绑定。
TAGBODY中的标签会具有词法作用域。如果(GO X)表达式实际上没有嵌入到其中，则它会发生错误。TAGBODY包含标签X。但是当TAGBODY执行终了时，标签的绑定就会消失，因为它们具有动态作用域。如果以调用一个词法闭包重新进入该代码区块，那么这个闭包的内文无法借由GO将控制转移到标签中：
  (defvar *stashed*) ;; will hold a function

  (tagbody
    (setf *stashed* (lambda () (go some-label)))
    (go end-label) ;; skip the (print "Hello")
   some-label
    (print "Hello")
   end-label)
  -> NIL
执行TAGBODY时，它首先评估以setf形式指向函数的特殊变量*stashed*，然后(go end-label)将控件转移到终了标签，跳过代码(print "Hello")。由于终了标签位于TAGBODY的末端，于是终止并返回NIL值。假设现在调用先前指向的函数：
  (funcall *stashed*) ;; Error!
这种状况是错误的。一个实作的错误回应该包含错误条件讯息，例如“GO: tagbody for tag SOME-LABEL has already been left”。该函数尝试评估(go some-label)，它是词法地嵌入到TAGBODY中并解析为标签。然而TAGBODY被跳过了而没有执行（其作用域已经结束），故无法再转移控制。
Lisp中的区域函数绑定具有词法作用域，预设情况下变量绑定也同样为词法作用域。与GO标签对比，它们的作用域是范围不定的。当一个词法的函数或变量绑定时，既然可以对其引用参照，该绑定就会持续存在，即使在建立该绑定的结构已经终止后。参照到词法变量和函数，在其建立结构终止后，可以借由词法的闭包来实现。
Common Lisp对于变量的预设模式是词法绑定。对于个别符号可用区域声明，或全局的声明，来切换成动态作用域。而后者可能隐含地透过如DEFVAR或DEFPARAMETER，这样的构造使符号成为全局可见的。Common Lisp编程中惯例以开头和结尾星号*，将特殊变量（即处于动态作用域的）包括起来，这称为“耳罩惯例”。遵循此惯例的效果，即为特殊变量创建了一个单独的命名空间，则应该处于词法作用域的变量不会被意外地特殊化。
几个原因使得词法作用域有用。
首先，变量和函数的参照可以被编译成高效的机器码，因为执行期环境的结构相对简单。在许多情况下它可以优化堆叠存储，因此开启和关闭的词法作用域前置开销最小。即使在必定要产生完整闭包的情况下，存取闭包的环境仍然是有效率的；每个变量通常会转成一个绑定向量之中的偏移量，因此变量的参照就成为简单的加载，或是以基底-加-偏移寻址模式表示的存储指令。
其次词法作用域（与不定范围结合）可以创造出词汇闭包，从而产生了中心以函数作为第一类物件的编程范式，这是函数式编程的根本。
第三，也许最重要的是，即使没有用到词法的闭包，词法作用域的运用，会将程序模组与不需要的交互影响隔离开来。由于可见性受到限制，词法变量是私有的。如果一个模组A绑定一个词法变量X，并呼叫另一个模组B，则参照B其中的变量X，不会被意外地解析成在A中绑定的X。B根本无法存取X。对于需使用变量进行有规则的交互作用情况，Common Lisp提供了特殊变量。特殊变量允许一个模组A设置变量X的绑定，使另一模组B能看见并从A调用其中的X。能够做到这一点是个优势，能够防止它发生也是个优势；因此Common Lisp同时支援词法和动态作用域两者。

使用宏定义控制结构的范例

Lisp编程人员能够利用宏来创造新的语法形式。典型的用途是创建新的控制结构。

此处提供一个until循环结构的宏范例，其语法如下：
(until test form*)
until宏的定义：
(defmacro until (test &body body)
  (let ((start-tag (gensym "START"))
        (end-tag   (gensym "END")))
    `(tagbody ,start-tag
              (when ,test (go ,end-tag))
              (progn ,@body)
              (go ,start-tag)
              ,end-tag)))
tagbody是一个基本的Common Lisp运算子，它提供了命名标签的能力，并使用go形式跳转到这些标签。

反引号`的用途类似单引号'（相当于quote函数，引用形式当成资料而不求值），它还是一个可作代码模板

的符号，其中需要求值的形式参数以逗号,开头填入模板；而以,@符号为开头的形式参数，其中嵌套的内容会

再被拆解评估。tagbody形式测试结束条件。如果条件为真，则跳转到结束标签；否则执行主体的代码，

然后跳转到起始标记。
上述until宏的使用范例：
(until (= (random 10) 0)
  (write-line "Hello"))
利用macroexpand-1函数可以展开宏的代码。上例经过展开后的代码如下所示：
(TAGBODY
 #:START1136
 (WHEN (ZEROP (RANDOM 10))
   (GO #:END1137))
 (PROGN (WRITE-LINE "hello"))
 (GO #:START1136)
 #:END1137)
在宏展开期间，变量test的值为(= (random (10) 0)，变量body的值为((write "Hello"))，是一个列表形式。
符号通常会自动转成英文大写。这个TAGBODY扩展中带有两个标签符号，由GENSYM自动产生，并且不会被拘束到任何套件中（为待绑定的暂时自由变量）。两个go形式会跳转到这些标签，因为tagbody是Common Lisp中的基本运算子（并不是宏），因此它没有其它内容会再展开。展开形式中用到的when宏也会再展开。将一个宏完全展开为源代码的形式，被称为代码走开（code walking）。在已被完全展开的形式中，when宏会被基本运算子if代换：
(TAGBODY
 #:START1136
 (IF (ZEROP (RANDOM 10))
     (PROGN (GO #:END1137))
   NIL)
 (PROGN (WRITE-LINE "hello"))
 (GO #:START1136))
 #:END1137)
源码中所有包含的宏必须在展开之后，才能正常地评估或编译。宏可以理解为接受和返回抽象语法树（Lisp S-表达式）的函数。
这些函数会在求值器或编译器调用之前，将宏内容转换为完整的源码，Common Lisp中所提供的任何运算子都可用于编写宏。

条件系统

条件系统负责Common Lisp中的异常处理。它提供条件，处理程序和重新启动。条件是描述异常情况（例如错误）的物件。如果一个条件讯号被发出了，Common Lisp系统将搜索此条件类型的处理程序并调用它。处理程序现在可以搜索重新启动（restart），并使用这些重新启动之一来自动修复当前的问题，利用条件类型与条件物件的一部分所提供的任何相关资讯等，并调用相对的重新启动函数。
如果没有处理程序的代码，这些重新启动可以对使用者显示选项（作为使用者界面的一部分，例如除错器），让使用者选择和调用提供的重新启动选项。由于条件处理程序在错误的上下文中被调用（堆叠仍未清空），在许多情况下对错误的完全回复处理是可行的，而不同于其它的异常处理系统可能已经终止了当前的执行程序。除错器本身也可以使用*debugger-hook*这个动态变量来客制或替换。在unwind-protect中写明的代码，譬如作为终结，也会适当地被执行例外。
以下范例（使用 Symbolics Genera）中，使用者从读取求值打印循环（REPL，即顶层）呼叫一个test函数，尝试开启一个档案，而当此档案不存在时，Lisp系统则呈现四个重新启动的选项。使用者选择了s-B:这个重新启动选项，并输入不同的路径名称（以lispm-init.lisp取代了lispm-int.lisp）。使用者执行的源码中并没有包含任何错误处理。整个错误处理和重新启动代码是由Lisp系统本身所提供，它可以处理和修复错误，而不终止使用者执行中的程序码。
Command: (test ">zippy>lispm-int.lisp")

Error: The file was not found.
       For lispm:>zippy>lispm-int.lisp.newest

LMFS:OPEN-LOCAL-LMFS-1
   Arg 0: #P"lispm:>zippy>lispm-int.lisp.newest"

s-A, <Resume>: Retry OPEN of lispm:>zippy>lispm-int.lisp.newest
s-B:           Retry OPEN using a different pathname
s-C, <Abort>:  Return to Lisp Top Level in a TELNET server
s-D:           Restart process TELNET terminal

-> Retry OPEN using a different pathname
Use what pathname instead [default lispm:>zippy>lispm-int.lisp.newest]:
   lispm:>zippy>lispm-init.lisp.newest

...the program continues

Common Lisp 物件系统(CLOS)

Common Lisp包含了面向对象编程的工具包，Common Lisp物件系统或简称为CLOS，它是最强大的物件系统之一。Peter Norvig 解释了在具备CLOS的动态语言中，如何使用其功能（多重继承，混合，多方法，元类，方法组合等），以达成设计模式更简单的实现。曾经有几个扩展被提出来作为Common Lisp ANSI标准的面向对象编程应用，而最终采用了CLOS作为Common Lisp的标准物件系统。
CLOS是个具有多个分派和多重继承的动态物件系统，并且与静态语言（如C++ 或Java）中的OOP设施截然不同。作为动态物件系统，CLOS允许在执行时期对泛型函数和类别进行更改。方法可以添加和删除，类别可以添加和重新定义，物件可依照类别的变动更新，而物件所属的类别也可以更改。CLOS已经整合到ANSI Common Lisp中。泛型函数可以像普通函数一样使用，并且是第一类资料类型。每个CLOS类别都已被整合到Common Lisp类别系统中。
Common Lisp中许多型别都有一个相对应的类别。规范中没有说明CLOS实作的条件，CLOS进阶用法的可能性并不是Common Lisp的ANSI标准，CLOS的用处有更多的潜能。一般Common Lisp实作将CLOS用于路径名称、流、输入/输出、条件，CLOS本身等等。

编译器和直译器

早期Lisp方言的几个实现提供了直译器和编译器，不幸的是两者之间语义是不同的。这些早期的Lisps在编译器中实作了词法作用域，在直译器中实作了动态作用域。Common Lisp要求直译器和编译器两者皆预设使用词法作用域。Common Lisp标准描述了直译器和编译器的语义。可以使用compile
函数呼叫编译器，来编译各个函数，并使用compile-file函数编译源码档案。Common Lisp允许类型别声明，并提供产生编译器代码的选择。后者有优化参数可选择0（不重要）和3（最重要）之间的值：会影响到执行速度，空间，安全性，除错和编译速度。
还有一个函数用来评估Lisp源码：eval。eval将源码视为预先解析的S-表达式，而不像其它语言只当成字串处理。这样可以用常见的Lisp函数来建构代码，用来构造列表和符号，然后以eval函数来评估该代码。几个Common Lisp实作（如Clozure CL和SBCL）以它们的编译器来实现eval。这样子即使用eval函数进行评估时，源码也是会被编译。
使用compile-file函数呼叫档案编译器，产生的编译档称为fasl（快速加载，fast load）档案。这些fasl档案和源码档案都能以load功能，加载到运行的Common Lisp系统中。根据实作，档案编译器会产生字节码（例如Java虚拟机），C语言代码（然后以C编译器编译）或直接使用原生机器码。
即使源码已经完全被编译，Common Lisp实作可以和使用者互动。因此，Common Lisp的互动界面并非类比于直译脚本的设想。
这个语言区隔了读取时期、编译时期、加载时期和执行时期，并让使用者编程在需求的步骤中，也依照这些区别来执行所需的处理种类。
有些特殊的运算子特别适合互动式开发；譬如，若defvar还没有任何绑定时，则只对提供给它的变量进行赋值；而defparameter总是会执行赋值。在实时映像中互动地评估，编译和载入代码时，这种区别是有用的。还有一些功能也帮助撰写编译器和直译器。符号由第一类物件所组成，可由使用者的代码直接操纵。progv基本运算子允许以编程方式创造词法绑定，也可以运用套件。Lisp编译器本身在运行时可用来编译档案或单一函数，这使得Lisp成为其它编程语言的中途编译器或直译器变得容易。

生日悖论

以下程序计算一个房间内最小数量的人，其完全独特生日的概率小于50％（生日悖论，1 人的概率明显为100％，2 为 364/365 等）。答案是23。
;;  By convention, constants in Common Lisp are enclosed with + characters.(defconstant +year-size+ 365)(defun birthday-paradox (probability number-of-people)
  (let ((new-probability (* (/ (- +year-size+ number-of-people)
                               +year-size+)
                            probability)))
    (if (< new-probability 0.5)
        (1+ number-of-people)
        (birthday-paradox new-probability (1+ number-of-people)))))
使用REPL呼叫函数用例：
CL-USER > (birthday-paradox 1.0 1)
23

排序列表

我们定义一个人员类别和一个显示姓名和年龄的方法。接下来，我们将一组人定义为人物物件列表。然后我们遍历排序列表。
(defclass person ()
  ((name :initarg :name :accessor person-name)
   (age  :initarg :age  :accessor person-age))
  (:documentation "The class PERSON with slots NAME and AGE."))(defmethod display ((object person) stream)
  "Displaying a PERSON object to an output stream."
  (with-slots (name age) object
    (format stream "~a (~a)" name age)))(defparameter *group*
  (list (make-instance 'person :name "Bob"   :age 33)
        (make-instance 'person :name "Chris" :age 16)
        (make-instance 'person :name "Ash"   :age 23))
  "A list of PERSON objects.")(dolist (person (sort (copy-list *group*)
                      #'>
                      :key #'person-age))
  (display person *standard-output*)
  (terpri))
它以降序打印三个名字。
Bob (33)
Ash (23)
Chris (16)

平方指数

使用LOOP宏：
(defun power (x n)
  (loop with result = 1
        while (plusp n)
        when (oddp n) do (setf result (* result x))
        do (setf x (* x x)
                 n (truncate n 2))
        finally (return result)))
使用示例：
CL-USER > (power 2 200)
1606938044258990275541962092341162602522202993782792835301376
与内建的求幂函数比较：
CL-USER > (= (expt 2 200) (power 2 200))
T

Common Lisp与Scheme的比较

Common Lisp经常和Scheme互相比较，因为它们是最受欢迎的两种Lisp方言。Scheme早于CL，不仅来自同一个Lisp传统，而且来自同一位工程师Guy L. Steele，与Gerald Jay Sussman设计的，Guy L. Steele也担任过Common Lisp标准委员会的主席。
Common Lisp是一种普遍用途的的编程语言；相反的如Emacs Lisp和AutoLISP这两种Lisp的变体，则是嵌入特定产品作为扩展用的语言。与许多早期的Lisps不同，Common Lisp（Scheme同样）对源码直译和编译时，预设为词法变量作用域。
大部分Lisp系统（如ZetaLisp和Franz Lisp）的设计，促成了Common Lisp在直译器中使用动态作用域的变量，并在编译器中使用了词法作用域的变量。由于ALGOL 68的启发，Scheme引入了Lisp对词法作用域变量的单一使用；这被广泛认同是好主意。CL也支援动态作用域的变量，但必须将其显式声明为“特殊”。ANSI CL直译器和编译器之间的作用域界定是没有差别的。
Common Lisp有时被称为Lisp-2，而Scheme被称为Lisp-1。它指的是CL对函数和变量使用个别的命名空间（实际上CL有许多命名空间，例如go标签，block名称和loop关键字）。在涉及多个命名空间的权衡之间，CL与Scheme倡导者之间存在着长期的争议。在Scheme中（广义地）必须避免与函数名称互相冲突的变量名称；Scheme函数通常拥有名称为lis，lst或lyst的参数，以免与系统内建的list函数冲突。然而在CL中，在传递函数作为参数时一定要显式地引用函数的名称空间，这也是一个常见的事件，如前面小节中的排序编程范例。
在处理布尔逻辑值时，CL也与Scheme不同。Scheme使用特殊值#t和#f来表示逻辑真与假值。而CL遵循使用符号T和NIL的传统Lisp惯例，NIL同时也是空列表。在CL中任何非NIL值被条件处理为真，例如if；而在Scheme当中，所有非#f值被视为真。这些惯例约定允许这两种语言的一些运算子同时作为谓词（回应逻辑上的是非问题），并返回一个作用值进行进一步的计算，但在Scheme的布尔表达式中，等同于Common Lisp空列表的NIL值或'()，会被评估为真。
最后，Scheme的标准文件要求尾部呼叫优化，而CL标准没有。不过大多数CL实作会提供尾部呼叫优化，虽然通常只在程序员使用优化指令时。尽管如此，常见的CL编程风格并不偏好于Scheme中普遍使用的递归样式- 一个Scheme程序员会使用尾部递归表达式，CL使用者则通常会用do，dolist，loop等迭代表达式，或使用iterate套件来表达。