2.3 数据 (Data)

Lisp 提供了所有在其他语言找的到的,以及其他语言所找不到的数据类型。一个我们已经使用过的类型是整数(integer),整数用一系列的数字来表示,比如: 256 。另一个 Common Lisp 与多数语言有关,并很常见的数据类型是字符串(string),字符串用一系列被双引号包住的字符串表示,比如: "ora et labora" [3] 。整数与字符串一样,都是对自身求值的。

[3]“ora et labora” 是拉丁文,意思是祷告与工作。

有两个通常在别的语言所找不到的 Lisp 数据类型是符号(symbol)与列表(lists),符号是英语的单词 (words)。无论你怎么输入,通常会被转换为大写:

  1. > 'Artichoke
  2. ARTICHOKE

符号(通常)不对自身求值,所以要是想引用符号,应该像上例那样用 ' 引用它。

列表是由被括号包住的零个或多个元素来表示。元素可以是任何类型,包含列表本身。使用列表必须要引用,不然 Lisp 会以为这是个函数调用:

  1. > '(my 3 "Sons")
  2. (MY 3 "Sons")
  3. > '(the list (a b c) has 3 elements)
  4. (THE LIST (A B C) HAS 3 ELEMENTS)

注意引号保护了整个表达式(包含内部的子表达式)被求值。

你可以调用 list 来创建列表。由于 list 是函数,所以它的实参会被求值。这里我们看一个在函数 list 调用里面,调用 + 函数的例子:

  1. > (list 'my (+ 2 1) "Sons")
  2. (MY 3 "Sons")

我们现在来到领悟 Lisp 最卓越特性的地方之一。Lisp的程序是用列表来表示的。如果实参的优雅与弹性不能说服你 Lisp 表示法是无价的工具,这里应该能使你信服。这代表着 Lisp 程序可以写出 Lisp 代码。 Lisp 程序员可以(并且经常)写出能为自己写程序的程序。

不过得到第 10 章,我们才来考虑这种程序,但现在了解到列表和表达式的关系是非常重要的,而不是被它们搞混。这也就是为什么我们需要 quote 。如果一个列表被引用了,则求值规则对列表自身来求值;如果没有被引用,则列表被视为是代码,依求值规则对列表求值后,返回它的值。

  1. > (list '(+ 2 1) (+ 2 1))
  2. ((+ 2 1) 3)

这里第一个实参被引用了,所以产生一个列表。第二个实参没有被引用,视为函数调用,经求值后得到一个数字。

在 Common Lisp 里有两种方法来表示空列表。你可以用一对不包括任何东西的括号来表示,或用符号 nil 来表示空表。你用哪种表示法来表示空表都没关系,但它们都会被显示为 nil

  1. > ()
  2. NIL
  3. > nil
  4. NIL

你不需要引用 nil (但引用也无妨),因为 nil 是对自身求值的。