欢迎来到Lisp
本章旨在让你尽快开始编程。到本章结束时,你将了解足够的Common Lisp知识来开始编写程序。
2.1 形式
对于Lisp来说尤其如此,你通过使用它来学习它,因为Lisp是一种交互式语言。任何Lisp系统都包含一个称为toplevel的交互式前端。你将Lisp表达式输入到toplevel中,系统会显示它们的值。Lisp通常会显示一个提示符来告诉你它在等待你输入内容。许多Common Lisp实现使用>作为toplevel提示符。这就是我们在这里要使用的。
最简单的Lisp表达式之一是整数。如果我们在提示符后输入1,
> 1
1
>
系统将打印它的值,然后是另一个提示符,表示它准备好接受更多输入。在这种情况下,显示的值与我们输入的相同。像1这样的数字被称为求值为自身。
当我们输入需要一些工作来求值的表达式时,生活变得更加有趣。例如,如果我们想要将两个数字相加,我们输入类似这样的内容:
> (+ 2 3)
5
在表达式(+ 2 3)中,+被称为运算符,数字2和3被称为参数。在日常生活中,我们会将这个表达式写为2 + 3,但在Lisp中,我们将+运算符放在前面,后面跟着参数,整个表达式用一对括号括起来:(+ 2 3)。这被称为前缀表示法,因为运算符在前。
这种写表达式的方式起初可能看起来很奇怪,但实际上这种表示法是Lisp最棒的特点之一。例如,如果我们想要将三个数字相加,在普通表示法中我们必须使用+两次,2 + 3 + 4,而在Lisp中我们只需添加另一个参数:(+ 2 3 4)
我们通常使用+的方式是,它必须恰好有两个参数:一个在左边,一个在右边。前缀表示法的灵活性意味着,在Lisp中,+可以接受任意数量的参数,包括无参数:
> (+)
0
> (+ 2)
2
> (+ 2 3)
5
> (+ 2 3 4)
9
> (+ 2 3 4 5)
14
因为运算符可以接受不同数量的参数,我们需要括号来表示表达式的开始和结束。表达式可以嵌套。也就是说,表达式中的参数本身可能是复杂的表达式:
> (/ (- 7 1) (- 4 2))
3
用英语来说,这是七减一,除以四减二。
Lisp表示法的另一个美妙之处是:这就是全部了。所有Lisp表达式要么是原子,比如1,要么是列表,由零个或多个用括号括起来的表达式组成。这些都是有效的Lisp表达式:
2
(+ 2 3)
(+ 2 3 4)
(/ (- 7 1) (- 4 2))
正如我们将看到的,所有Lisp代码都采用这种形式。像C这样的语言有更复杂的语法:算术表达式使用中缀表示法;函数调用使用一种前缀表示法,参数用逗号分隔;表达式用分号分隔;代码块用大括号分隔。在Lisp中,我们使用单一的表示法来表达所有这些概念。
2.2 求值
在上一节中,我们将表达式输入到toplevel中,Lisp显示了它们的值。在本节中,我们更仔细地看看表达式是如何求值的。
在Lisp中,+是一个函数,像(+ 2 3)这样的表达式是一个函数调用。当Lisp求值函数调用时,它分两步进行:
- 首先从左到右求值参数。在这种情况下,每个参数都求值为自身,所以参数的值分别是2和3。
- 参数的值被传递给由运算符命名的函数。在这种情况下,它是+函数,返回5。
如果任何参数本身是函数调用,它们会根据相同的规则求值。所以当(/ (- 7 1) (- 4 2))被求值时,会发生以下情况:
- Lisp求值(- 7 1):7求值为7,1求值为1。这些值被传递给函数-,返回6。
- Lisp求值(- 4 2):4求值为4,2求值为2。这些值被传递给函数-,返回2。
- 值6和2被发送给函数/,返回3。
并非Common Lisp中的所有运算符都是函数,但大多数都是。函数调用总是以这种方式求值。参数从左到右求值,它们的值被传递给函数,函数返回整个表达式的值。这被称为Common Lisp的求值规则。
一个不遵循Common Lisp求值规则的运算符是quote。quote运算符是一个特殊运算符,意味着它有自己独特的求值规则。规则是:什么都不做。quote运算符接受一个参数,只是原样返回它:
> (quote (+ 3 5))
(+ 3 5)
为了方便起见,Common Lisp将’定义为quote的缩写。你可以通过在任何表达式前面加上’来获得调用quote的效果:
> '(+ 3 5)
(+ 3 5)
使用缩写比写出整个quote表达式要常见得多。Lisp提供quote作为保护表达式不被求值的一种方式。下一节将解释这种保护如何有用。
注意:这是ANSI Common Lisp的第2章,涵盖了基本的Lisp语法、求值、表达式、列表和函数。本章包括交互式编程和基本概念的示例。