欢迎来到Lisp

Paul Graham 1995-01-01

欢迎来到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求值函数调用时,它分两步进行:

  1. 首先从左到右求值参数。在这种情况下,每个参数都求值为自身,所以参数的值分别是2和3。
  2. 参数的值被传递给由运算符命名的函数。在这种情况下,它是+函数,返回5。

如果任何参数本身是函数调用,它们会根据相同的规则求值。所以当(/ (- 7 1) (- 4 2))被求值时,会发生以下情况:

  1. Lisp求值(- 7 1):7求值为7,1求值为1。这些值被传递给函数-,返回6。
  2. Lisp求值(- 4 2):4求值为4,2求值为2。这些值被传递给函数-,返回2。
  3. 值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语法、求值、表达式、列表和函数。本章包括交互式编程和基本概念的示例。

Welcome to Lisp

This chapter aims to get you programming as soon as possible. By the end of it you will know enough Common Lisp to begin writing programs.

2.1 Form

It is particularly true of Lisp that you learn it by using it, because Lisp is an interactive language. Any Lisp system will include an interactive front-end called the toplevel. You type Lisp expressions into the toplevel, and the system displays their values. Lisp usually displays a prompt to tell you that it’s waiting for you to type something. Many implementations of Common Lisp use > as the toplevel prompt. That’s what we’ll use here.

One of the simplest kinds of Lisp expression is an integer. If we enter 1 after the prompt,

> 1
1
>

the system will print its value, followed by another prompt, to say that it’s ready for more. In this case, the value displayed is the same as what we typed. A number like 1 is said to evaluate to itself.

Life gets more interesting when we enter expressions that take some work to evaluate. For example, if we want to add two numbers together, we type something like:

> (+ 2 3)
5

In the expression (+ 2 3), the + is called the operator, and the numbers 2 and 3 are called the arguments. In everyday life, we would write this expression as 2 + 3, but in Lisp we put the + operator first, followed by the arguments, with the whole expression enclosed in a pair of parentheses: (+ 2 3). This is called prefix notation, because the operator comes first.

It may at first seem a strange way to write expressions, but in fact this notation is one of the best things about Lisp. For example, if we want to add three numbers together, in ordinary notation we have to use + twice, 2 + 3 + 4 while in Lisp we just add another argument: (+ 2 3 4)

The way we ordinarily use +, it must have exactly two arguments: one on the left and one on the right. The flexibility of prefix notation means that, in Lisp, + can take any number of arguments, including none:

> (+)
0
> (+ 2)
2
> (+ 2 3)
5
> (+ 2 3 4)
9
> (+ 2 3 4 5)
14

Because operators can take varying numbers of arguments, we need parentheses to show where an expression begins and ends. Expressions can be nested. That is, the arguments in an expression may themselves be complex expressions:

> (/ (- 7 1) (- 4 2))
3

In English, this is seven minus one, divided by four minus two.

Another beauty of Lisp notation is: this is all there is. All Lisp expressions are either atoms, like 1, or lists, which consist of zero or more expressions enclosed in parentheses. These are valid Lisp expressions:

2
(+ 2 3)
(+ 2 3 4)
(/ (- 7 1) (- 4 2))

As we will see, all Lisp code takes this form. A language like C has a more complicated syntax: arithmetic expressions use infix notation; function calls use a sort of prefix notation, with the arguments delimited by commas; expressions are delimited by semicolons; and blocks of code are delimited by curly brackets. In Lisp, we use a single notation to express all these ideas.

2.2 Evaluation

In the previous section, we typed expressions into the toplevel, and Lisp displayed their values. In this section we take a closer look at how expressions are evaluated.

In Lisp, + is a function, and an expression like (+ 2 3) is a function call. When Lisp evaluates a function call, it does so in two steps:

  1. First the arguments are evaluated, from left to right. In this case, each argument evaluates to itself, so the values of the arguments are 2 and 3, respectively.
  2. The values of the arguments are passed to the function named by the operator. In this case, it is the + function, which returns 5.

If any of the arguments are themselves function calls, they are evaluated according to the same rules. So when (/ (- 7 1) (- 4 2)) is evaluated, this is what happens:

  1. Lisp evaluates (- 7 1): 7 evaluates to 7 and 1 evaluates to 1. These values are passed to the function -, which returns 6.
  2. Lisp evaluates (- 4 2): 4 evaluates to 4 and 2 evaluates to 2. These values are passed to the function -, which returns 2.
  3. The values 6 and 2 are sent to the function /, which returns 3.

Not all the operators in Common Lisp are functions, but most are. And function calls are always evaluated this way. The arguments are evaluated left-to-right, and their values are passed to the function, which returns the value of the expression as a whole. This is called the evaluation rule for Common Lisp.

One operator that doesn’t follow the Common Lisp evaluation rule is quote. The quote operator is a special operator, meaning that it has a distinct evaluation rule of its own. And the rule is: do nothing. The quote operator takes a single argument, and just returns it verbatim:

> (quote (+ 3 5))
(+ 3 5)

For convenience, Common Lisp defines ’ as an abbreviation for quote. You can get the effect of calling quote by affixing a ’ to the front of any expression:

> '(+ 3 5)
(+ 3 5)

It is much more common to use the abbreviation than to write out the whole quote expression. Lisp provides the quote as a way of protecting expressions from evaluation. The next section will explain how such protection can be useful.


Note: This is Chapter 2 of ANSI Common Lisp, covering basic Lisp syntax, evaluation, expressions, lists, and functions. The chapter includes examples of interactive programming and fundamental concepts.