# LISP公理——七个原始操作符
我们先定义表达式。表达式或是一个原子(atom),它是一个字母序列(如 foo),或是一个由零个或多个表达式组成的表(list),表达式之间用空格分开,放入一对括号中。
以下是一些表达式:
foo
()
(foo)
(foo bar)
(a b (c) d)
最后一个表达式是由四个元素组成的表,第三个元素本身是由一个元素组成的表。
在算术中表达式 1 + 1 得出值正确的Lisp表达式也有值。
如果表达式e得出值v,我们说e返回v。
下一步我们将定义几种表达式以及它们的返回值。
如果一个表达式是表,我们称第一个元素为操作符,其余的元素为自变量。
接下来将定义七个原始(从公理的意义上说)操作符:
quote、atom、eq、car、cdr、cons和cond。
1.(quote x)
返回x。为了可读性我们把(quote x)简记 为’x。
$ (quote a)
a
$ 'a
a
$ (quote (a b c))
(a b c)
2.(atom x)
返回原子t。如果x的值是一个原子或是空表,否则返回()。
在Lisp中,我们按惯例用原子t表示真,而用空表表示假。
$ (atom 'a)
t
$ (atom '(a b c))
()
$ (atom '())
t
既然有了一个自变量需要求值的操作符,我们可以看一下quote的作用。
通过引用(quote)一个表,我们避免它被求值。
一个未被引用的表作为自变量传给像atom这样的操作符将被视为代码:
$ (atom (atom 'a))
t
反之一个被引用的表仅被视为表,在此例中就是有两个元素的表:
$ (atom '(atom 'a))
()
这与我们在英语中使用引号的方式一致。
Cambridge(剑桥)是一个位于麻萨诸塞州有90000人口的城镇,而“Cambridge”是一个由9个字母组成的单词。
引用看上去可能有点奇怪,因为极少有其它语言有类似的概念。它和Lisp最与众不同的特征紧密联系:代码和数据由相同的数据结构构成,而我们用quote操作符来区分它们。
3.(eq x y)
返回t如果x和y的值是同一个原子或都是空表,否则返回()。
$ (eq 'a 'a)
t
$ (eq 'a 'b)
()
$ (eq '() '())
t
4.(car x)
期望x的值是一个表并且返回x的第一个元素。
$ (car '(a b c))
a
5.(cdr x)
期望x的值是一个表并且返回x的第一个元素之后的所有元素。
$ (cdr '(a b c))
(b c)
6.(cons x y)
期望y的值是一个表并且返回一个新表,它的第一个元素是x的值,后面跟着y的值的各个元素。
$ (cons 'a '(b c))
(a b c)
$ (cons 'a (cons 'b (cons 'c '())))
(a b c)
$ (car (cons 'a '(b c)))
a
$ (cdr (cons 'a '(b c)))
(b c)
7.(cond (…) …(…))
它 的求值规则如下:
p表达式依次求值直到有一个返回t。
如果能找到这样的p表达式,相应的e表达式的值作为整个cond表达式的返回值。
$ (cond ((eq 'a 'b) 'first)
((atom 'a) 'second))
second
当表达式以七个原始操作符中的五个开头时,它的自变量总是要求值的。
我们称这样的操作符为函数。