Lisp入门教程
Common LISP Hints
? ? ? ? ? ? ? ? ? ? ? ? ?Geoffrey J. Gordon
? ? ? ? ? ? ? ? ? ? ? ? < ggordon@cs.cmu.edu >
? ? ? ? ? ? ? ? ? ? ? Friday, February 5, 1993
? ? ? ? ? ? ? ? ? ? ? ? ? ?Modified by
? ? ? ? ? ? ? ? ? ? ? ? ? ?Bruno Haible
? ? ? ? ? ? ? ?< haible@ma2s2.mathematik.uni-karlsruhe.de >
? ? ? ? ? ? ? ? ? ? ? ? ? 簡(jiǎn)體中文版翻譯:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?劉鑫
? ? ? ? ? ? ? ? ? ? ? ?< March.Liu@gmail.com >
Note: This tutorial introduction to Common Lisp was written for the
CMU environment, so some of the details of running lisp toward the end
may differ from site to site.
注意:這份 Common Lisp 入門教程是針對(duì) CMU
環(huán)境編寫,所以在其它環(huán)境運(yùn)行
LISP時(shí)可能會(huì)有細(xì)節(jié)上的區(qū)別。
Further Information
附:
The best LISP textbook I know of is
?Guy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984.
據(jù)我所知最好的 Lisp 書籍是:
?Guy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984.
The first edition is easier to read; the second describes a more recent
standard. (The differences between the two standards shouldn't affect
casual programmers.)
第一版很容易閱讀,第二版介紹了更新的標(biāo)準(zhǔn)。(兩個(gè)標(biāo)準(zhǔn)的差異很 小,對(duì)于粗
心的程序員沒有什么區(qū)別。)
A book by Dave Touretsky has also been recommended to me, although I
haven't read it, so I can't say anything about it.
我還記得 Dave Touretsky
寫了一本,不過我從來沒讀過,所以不能對(duì)那本書
發(fā)表評(píng)論。
Symbols
符號(hào)
A symbol is just a string of characters. There are restrictions on what
you can include in a symbol and what the first character can be, but as
long as you stick to letters, digits, and hyphens, you'll be safe.
(Except that if you use only digits and possibly an initial hyphen,
LISP will think you typed an integer rather than a symbol.) Some
examples of symbols:
符號(hào)僅僅是字符串。你可以在符號(hào)中包含字母、數(shù)字、連接符等等,唯一的限制就
是要以字母開頭。(如果你只輸入數(shù)字,最多再以一個(gè)連接符開頭的話,LISP會(huì)認(rèn)
為你輸入了一個(gè)整數(shù)而不是符號(hào)。)例如:
? ? ? ?a
? ? ? ?b
? ? ? ?c1
? ? ? ?foo
? ? ? ?bar
? ? ? ?baaz-quux-garply
Some things you can do with symbols follow. (Things after a ">" prompt
are what you type to the LISP interpreter, while other things are what
the LISP interpreter prints back to you. The ";" is LISP's comment
character: everything from a ";" to the end of line is ignored.)
接下來我們可以做些事情。(">"標(biāo)記表示你向LISP輸入的東西,其它的是LISP
打印返回給你的。";"是LISP的注釋符:";"后面的整行都會(huì)被忽略。)
> (setq a 5) ? ? ? ? ? ?;store a number as the value of a symbol
5
> a ? ? ? ? ? ? ? ? ? ? ;take the value of a symbol
5
> (let ((a 6)) a) ? ? ? ;bind the value of a symbol temporarily to 6
6
> a ? ? ? ? ? ? ? ? ? ? ;the value returns to 5 once the let is finished
5
> (+ a 6) ? ? ? ? ? ? ? ;use the value of a symbol as an argument to a function
11
> b ? ? ? ? ? ? ? ? ? ? ;try to take the value of a symbol which has no value
Error: Attempt to take the value of the unbound symbol B
There are two special symbols, t and nil. The value of t is defined
always to be t, and the value of nil is defined always to be nil. LISP
uses t and nil to represent true and false. An example of this use is
in the if statement, described more fully later:
有兩個(gè)特殊的符號(hào), t 和 nil 。 t 的值總是定義為 t
,nil 的值總是定義為
nil 。LISP用 t 和 nil 代表 true 和
false。以下是使用這個(gè)功能的 if 語句
,后面再做詳細(xì)說明:
> (if t 5 6)
5
> (if nil 5 6)
6
> (if 4 5 6)
5
The last example is odd but correct: nil means false, and anything else
means true. (Unless we have a reason to do otherwise, we use t to mean
true, just for the sake of clarity.)
最后一個(gè)例子看起來很怪,但是沒有錯(cuò):nil 代表 false
,其它任意值代表 true。
(為了代碼清晰,在沒有什么特別原因的情況下,我們用t代表true。)
Symbols like t and nil are called self-evaluating symbols, because
they evaluate to themselves. There is a whole class of self-evaluating
symbols called keywords; any symbol whose name starts with a colon is a
keyword. (See below for some uses for keywords.) Some examples:
t 和 nil
這樣的符號(hào)被稱為自解析符號(hào),因?yàn)樗麄兘馕鰹樽陨怼W越馕龇?hào)稱為
關(guān)鍵字;任一以冒號(hào)開頭的符號(hào)都是關(guān)鍵字。(下面是一些關(guān)鍵字的應(yīng)用)如下
所示:
> :this-is-a-keyword
:THIS-IS-A-KEYWORD
> :so-is-this
:SO-IS-THIS
> :me-too
:ME-TOO
Numbers
數(shù)值
An integer is a string of digits optionally preceded by + or -. A real
number looks like an integer, except that it has a decimal point and
optionally can be written in scientific notation. A rational looks like
two integers with a / between them. LISP supports complex numbers,
which are written #c(r i) (where r is the real part and i is the
imaginary part). A number is any of the above. Here are some numbers:
數(shù)值類型是數(shù)字文本,可能會(huì)以 + 或 -
開頭。實(shí)數(shù)和整數(shù)很相像,但是它帶有
小數(shù)點(diǎn),還可能寫成科學(xué)計(jì)數(shù)法。有理數(shù)就像是兩個(gè)整數(shù)之間帶有一個(gè)/。LISP支
持復(fù)數(shù),寫為#c(r
i)(r表示實(shí)部,i表示虛部)。以上統(tǒng)稱為數(shù)值。下面是一
些數(shù)值:
? ? ? ?5
? ? ? ?17
? ? ? ?-34
? ? ? ?+6
? ? ? ?3.1415
? ? ? ?1.722e-15
? ? ? ?#c(1.722e-15 0.75)
The standard arithmetic functions are all available: +, -, *, /, floor,
ceiling, mod, sin, cos, tan, sqrt, exp, expt, and so forth. All of them
accept any kind of number as an argument. +, -, *, and / return a
number according to type contagion: an integer plus a rational is a
rational, a rational plus a real is a real, and a real plus a complex
is a complex. Here are some examples:
標(biāo)準(zhǔn)的計(jì)算函數(shù)包括: +, -, *, /, floor, ceiling, mod, sin,
cos, tan,
sqrt, exp, expt
等等。所有這些函數(shù)都可以接受任意數(shù)值類型參數(shù)。+、-、*
和
/返回盡可能大的類型:一個(gè)整數(shù)加一個(gè)有理數(shù)返回有理數(shù),一個(gè)有理數(shù)加一個(gè)實(shí)數(shù)
是一個(gè)實(shí)數(shù),一個(gè)實(shí)數(shù)加一個(gè)復(fù)數(shù)是一個(gè)復(fù)數(shù)。如下所示:
> (+ 3 3/4) ? ? ? ? ? ? ;type contagion
15/4
> (exp 1) ? ? ? ? ? ? ? ;e
2.7182817
> (exp 3) ? ? ? ? ? ? ? ;e*e*e
20.085537
> (expt 3 4.2) ? ? ? ? ?;exponent with a base other than e
100.90418
> (+ 5 6 7 (* 8 9 10)) ?;the fns +-*/ all accept multiple arguments
There is no limit to the absolute value of an integer except the memory
size of your computer. Be warned that computations with bignums (as
large integers are called) can be slow. (So can computations with
rationals, especially compared to the corresponding computations with
small integers or floats.)
對(duì)于整數(shù)來說,唯一的大小限制就是機(jī)器的內(nèi)存。當(dāng)然大數(shù)值運(yùn)算(這
會(huì)調(diào)用大整數(shù))可能會(huì)很慢。(因此我們可以計(jì)算有理數(shù),尤其是小整數(shù)和浮點(diǎn)數(shù)
的比較運(yùn)算)
Conses
A cons is just a two-field record. The fields are called "car" and
"cdr", for historical reasons. (On the first machine where LISP was
implemented, there were two instructions CAR and CDR which stood for
"contents of address register" and "contents of decrement register".
Conses were implemented using these two registers.)
cons
就是一個(gè)包含兩個(gè)字段的記錄。出于歷史原因,兩個(gè)字段分別被稱為
"car"和"cdr"。(在第一臺(tái)實(shí)現(xiàn)LISP的機(jī)器上,用CAR和CDR代表"地址寄
存器的內(nèi)容"和"指令寄存器的內(nèi)容"。Conses的實(shí)現(xiàn)主要依靠這兩個(gè)寄存器。)
Conses are easy to use:
Conses很容易使用:
> (cons 4 5) ? ? ? ? ? ?;Allocate a cons. Set the car to 4 and the cdr to 5.
(4 . 5)
> (cons (cons 4 5) 6)
((4 . 5) . 6)
> (car (cons 4 5))
4
> (cdr (cons 4 5))
5
Lists
You can build many structures out of conses. Perhaps the simplest is a
linked list: the car of each cons points to one of the elements of the
list, and the cdr points either to another cons or to nil. You can
create such a linked list with the list fuction:
你可以構(gòu)造conses之外的結(jié)構(gòu)。可能最簡(jiǎn)單的是鏈表:每一個(gè)cons的car指向鏈表
的一個(gè)元素,cdr指向另一個(gè)cons或者nil。我們可以使用list函數(shù)構(gòu)造鏈表。
> (list 4 5 6)
(4 5 6)
Notice that LISP prints linked lists a special way: it omits some of
the periods and parentheses. The rule is: if the cdr of a cons is nil,
LISP doesn't bother to print the period or the nil; and if the cdr of
cons A is cons B, then LISP doesn't bother to print the period for cons
A or the parentheses for cons B. So:
需要注意的是 LISP
用一種特殊的方式打印鏈表:它忽略掉某些分隔和括號(hào)。
規(guī)則如下:如果某個(gè) cons 的 cdr 是 nil ,LISP 不打印 nil
和段標(biāo)記,如果
cons A 的 cdr 是 cons B,LISP不打印 cons B 的括號(hào)和 cons A
的分隔符。
如下:
> (cons 4 nil)
(4)
> (cons 4 (cons 5 6))
(4 5 . 6)
> (cons 4 (cons 5 (cons 6 nil)))
(4 5 6)
The last example is exactly equivalent to the call (list 4 5 6). Note
that nil now means the list with no elements: the cdr of (a b), a list
with 2 elements, is (b), a list with 1 element; and the cdr of (b), a
list with 1 element, is nil, which therefore must be a list with no
elements.
最后一個(gè)例子相當(dāng)于調(diào)用(list 4 5 6)。要注意的是這里
nil 表示沒有元素的空
鏈表:包含兩個(gè)元素的鏈表(a
b)中,cdr是(b),一個(gè)含有單個(gè)元素的鏈表;包含
一個(gè)元素的鏈表(b),cdr是nil,故此這里必然是一個(gè)沒有元素的鏈表。
The car and cdr of nil are defined to be nil.
nil 的 car 和 cdr 定義為nil。
If you store your list in a variable, you can make it act like a stack:
如果你把鏈表存儲(chǔ)在變量中,可以將它當(dāng)作堆棧來使用:
> (setq a nil)
NIL
> (push 4 a)
(4)
> (push 5 a)
(5 4)
> (pop a)
5
> a
(4)
> (pop a)
4
> (pop a)
NIL
> a
NIL
Functions
You saw one example of a function above. Here are some more:
前面我們討論過一些函數(shù)的例子,這里還有更多:
> (+ 3 4 5 6) ? ? ? ? ? ? ? ? ? ;this function takes any number of arguments
18
> (+ (+ 3 4) (+ (+ 4 5) 6)) ? ? ;isn't prefix notation fun?
22
> (defun foo (x y) (+ x y 5)) ? ;defining a function
FOO
> (foo 5 0) ? ? ? ? ? ? ? ? ? ? ;calling a function
10
> (defun fact (x) ? ? ? ? ? ? ? ;a recursive function
? ?(if (> x 0)
? ? ?(* x (fact (- x 1)))
? ? ?1))
FACT
> (fact 5)
120
> (defun a (x) (if (= x 0) t (b (- x)))) ? ? ? ?;mutually recursive functions
A
> (defun b (x) (if (> x 0) (a (- x 1)) (a (+ x 1))))
B
> (a 5)
T
> (defun bar (x) ? ? ? ? ? ? ? ?;a function with multiple statements in
? ?(setq x (* x 3)) ? ? ? ? ? ?;its body -- it will return the value
? ?(setq x (/ x 2)) ? ? ? ? ? ?;returned by its final statement
? ?(+ x 4))
BAR
> (bar 6)
13
When we defined foo, we gave it two arguments, x and y. Now when we
call foo, we are required to provide exactly two arguments: the first
will become the value of x for the duration of the call to foo, and the
second will become the value of y for the duration of the call. In
LISP, most variables are lexically scoped; that is, if foo calls bar
and bar tries to reference x, bar will not get foo's value for x.
當(dāng)我們定義函數(shù)的時(shí)候,設(shè)定了兩個(gè)參數(shù),x 和
y。現(xiàn)在當(dāng)我們調(diào)用 foo,需要
給出兩個(gè)參數(shù):第一個(gè)在 foo 函數(shù)調(diào)用時(shí)成為 x
的值,第二個(gè)成為 y 的值。
在LISP中,大部分的變量都是局部的,如果 foo 調(diào)用了
bar ,bar中雖然使用了
名字為x的引用,但bar 得不到 foo 中的 x 。
The process of assigning a symbol a value for the duration of some
lexical scope is called binding.
在調(diào)用過程中給一個(gè)符號(hào)賦值的操作被稱為綁定。
You can specify optional arguments for your functions. Any argument
after the symbol &optional is optional:
我們可以給函數(shù)指定可選參數(shù),在符號(hào)&optional
之后的參數(shù)是可選參數(shù):
> (defun bar (x &optional y) (if y x 0))
BAR
> (defun baaz (&optional (x 3) (z 10)) (+ x z))
BAAZ
> (bar 5)
0
> (bar 5 t)
5
> (baaz 5)
15
> (baaz 5 6)
11
> (baaz)
13
It is legal to call the function bar with either one or two arguments.
If it is called with one argument, x will be bound to the value of that
argument and y will be bound to nil; if it is called with two
arguments, x and y will be bound to the values of the first and second
argument, respectively.
bar函數(shù)的調(diào)用規(guī)則是要給出一個(gè)或兩個(gè)參數(shù)。如果它用一個(gè)參數(shù)調(diào)用,x
將會(huì)綁
定到這個(gè)參數(shù)值上,而 y 就是
nil;如果用兩個(gè)參數(shù)調(diào)用它,x和y會(huì)分別綁定
到第一和第二個(gè)值上。
The function baaz has two optional arguments. It specifies a default
value for each of them: if the caller specifies only one argument, z
will be bound to 10 instead of to nil, and if the caller specifies no
arguments, x will be bound to 3 and z to 10.
baaz
函數(shù)有兩個(gè)可選參數(shù)。它為它們分別提供了默認(rèn)值:如果調(diào)用者只給出了一
個(gè)參數(shù),z會(huì)綁定為10而不是nil,如果調(diào)用者沒有給出參數(shù),x會(huì)綁定為3,而z綁
定為10。
You can make your function accept any number of arguments by ending its
argument list with an &rest parameter. LISP will collect all arguments
not otherwise accounted for into a list and bind the &rest parameter to
that list. So:
在參數(shù)列表的最后設(shè)置一個(gè) &rest
參數(shù),可以使我們的函數(shù)接受任意數(shù)目的參數(shù)。
LISP把所有的附加參數(shù)都放進(jìn)一個(gè)鏈表并綁定到 &rest
參數(shù)。如下:
> (defun foo (x &rest y) y)
FOO
> (foo 3)
NIL
> (foo 4 5 6)
(5 6)
Finally, you can give your function another kind of optional argument
called a keyword argument. The caller can give these arguments in any
order, because they're labelled with keywords.
最后,我們可以為函數(shù)指定一種被稱為關(guān)鍵字參數(shù)的可選參數(shù)。調(diào)用者可以用
任意順序調(diào)用這些參數(shù),因?yàn)樗麄円呀?jīng)通過關(guān)鍵字標(biāo)示出來。
> (defun foo (&key x y) (cons x y))
FOO
> (foo :x 5 :y 3)
(5 . 3)
> (foo :y 3 :x 5)
(5 . 3)
> (foo :y 3)
(NIL . 3)
> (foo)
(NIL)
An &key parameter can have a default value too:
關(guān)鍵字參數(shù)也可以有默認(rèn)值:
> (defun foo (&key (x 5)) x)
FOO
> (foo :x 7)
7
> (foo)
5
Printing
Some functions can cause output. The simplest one is print, which
prints its argument and then returns it.
某些函數(shù)可以用來輸出。最簡(jiǎn)單的一個(gè)是
print,它可以打印參數(shù)并且返回
它們。
> (print 3)
3
3
The first 3 above was printed, the second was returned.
首先打印3,然后返回它。
If you want more complicated output, you will need to use format.
Here's an example:
如果你需要更復(fù)雜的輸出,可能會(huì)用到
format,這里有個(gè)例子:
> (format t "An atom: ~S~%and a list: ~S~%and an integer: ~D~%"
? ? ? ? ?nil (list 5) 6)
An atom: NIL
and a list: (5)
and an integer: 6
The first argument to format is either t, nil, or a stream. T specifies
output to the terminal. Nil means not to print anything but to return a
string containing the output instead. Streams are general places for
output to go: they can specify a file, or the terminal, or another
program. This handout will not describe streams in any further detail.
第一個(gè)參數(shù)可以是 t,nil
或者一個(gè)流。t意味著輸出到終端;nil意味著不打印
任何東西,而是把它返回。流是用于輸出的通用方式:它可以是一個(gè)指定的文件,
或者一個(gè)終端,或者另一個(gè)程序。這里不再詳細(xì)描述流的更多細(xì)節(jié)。
The second argument is a formatting template, which is a string
optionally containing formatting directives.
第二個(gè)參數(shù)是個(gè)格式化模版,即一個(gè)包含格式化設(shè)定的字符串。
All remaining arguments may be referred to by the formatting
directives. LISP will replace the directives with some appropriate
characters based on the arguments to which they refer and then print
the resulting string.
所有其它的參數(shù)由格式化設(shè)定引用。LISP會(huì)根據(jù)標(biāo)示所引用的參數(shù),將其替換
為合適的字符,并返回結(jié)果字符串。
Format always returns nil unless its first argument is nil, in which
case it prints nothing and returns a string.
如果format的第一個(gè)參數(shù)是 nil
,它返回一個(gè)字符串,什么也不打印,否則
它總是返回 nil 。
There are three different directives in the above example: ~S, ~D, and
~%. The first one accepts any LISP object and is replaced by a printed
representation of that object (the same representation which is
produced by print). The second one accepts only integers. The third one
doesn't refer to an argument; it is always replaced by a carriage
return.
前面的例子中有三種不同的標(biāo)示:~S,~D和~%。第一個(gè)接受任意LISP對(duì)象并且將
其替換為這個(gè)對(duì)象的打印描述(與使用print打印出的描述信息相同)。第二個(gè)
Another useful directive is ~~, which is replaced by a single ~.
另一個(gè)常用的標(biāo)示是~~,它替換為單個(gè)~。
Refer to a LISP manual for (many, many) additional formatting
directives.
LISP手冊(cè)中介紹了其它(很多,很多)的格式化標(biāo)示。
Forms and the Top-Level Loop
The things which you type to the LISP interpreter are called forms; the
LISP interpreter repeatedly reads a form, evaluates it, and prints the
result. This procedure is called the read-eval-print loop.
我們輸入到LISP解釋器的東西被稱為語句;LISP解釋器逐條循環(huán)讀取每條語句,
進(jìn)行解析,將結(jié)果打印出來。這個(gè)過程被稱為讀取-解析-打印循環(huán)。
Some forms will cause errors. After an error, LISP will put you into
the debugger so you can try to figure out what caused the error. LISP
debuggers are all different; but most will respond to the command
"help" or ":help" by giving some form of help.
某些語句會(huì)發(fā)生錯(cuò)誤,LISP會(huì)引領(lǐng)我們進(jìn)入調(diào)試器,以便我們找出錯(cuò)誤原因。
LISP的各種調(diào)試器有很多差異,不過使用"help"或":help"命令就會(huì)給出一
些語句幫助。
In general, a form is either an atom (for example, a symbol, an
integer, or a string) or a list. If the form is an atom, LISP evaluates
it immediately. Symbols evaluate to their value; integers and strings
evaluate to themselves. If the form is a list, LISP treats its first
element as the name of a function; it evaluates the remaining elements
recursively, and then calls the function with the values of the
remaining elements as arguments.
通常,一個(gè)語句是一個(gè)原子(例如,一個(gè)符號(hào)或者整數(shù),或者字符串)或者一個(gè)列表,
如果換某個(gè)語句是原子,LISP立即解析它。符號(hào)解析為它們的值;整數(shù)和字符串解析
為它們自身。如果語句是一個(gè)列表,LISP視它的第一個(gè)元素為函數(shù)名;它遞歸的解析
其余的元素,然后將它們的值作為參數(shù)來調(diào)用這個(gè)函數(shù)。
For example, if LISP sees the form (+ 3 4), it treats + as the name of
a function. It then evaluates 3 to get 3 and 4 to get 4; finally it
calls + with 3 and 4 as the arguments. The + function returns 7, which
LISP prints.
例如,如果LISP遇到語句 (+ 3 4),它嘗試將 +
作為函數(shù)名。然后將3解析為3,4解
析為4;最后用3和4作為參數(shù)調(diào)用+。LISP打印出 +
函數(shù)的返回值7。
The top-level loop provides some other conveniences; one particularly
convenient convenience is the ability to talk about the results of
previously typed forms. LISP always saves its most recent three
results; it stores them as the values of the symbols *, **, and ***.
For example:
頂級(jí)循環(huán)還提供了一些其它的便利;一個(gè)特別方便的地方就是獲取以前輸入的
語句的結(jié)果。LISP總會(huì)保存最近三個(gè)結(jié)果;它將它們保存在*,**和***三個(gè)符
號(hào)的值中,例如:
> 3
3
> 4
4
> 5
5
> ***
3
> ***
4
> ***
5
> **
4
> *
4
Special forms
There are a number of special forms which look like function calls but
aren't. These include control constructs such as if statements and do
loops; assignments like setq, setf, push, and pop; definitions such as
defun and defstruct; and binding constructs such as let. (Not all of
these special forms have been mentioned yet. See below.)
有幾個(gè)特殊語句看起來像函數(shù)調(diào)用,但其實(shí)不是。這里面包括流程控制語句,例
如 if 語句和 do loops;賦值語句,例如 setq,
setf,push和pop;定義語句
例如 defun 和 defstruct;以及綁定構(gòu)造,如
let。(這里沒有提及所有的特殊
語句。我們繼續(xù)。)
One useful special form is the quote form: quote prevents its argument
from being evaluated. For example:
一個(gè)很有用的特殊語句是 quote
:quote取消其參數(shù)的綁定狀態(tài)。例如:
> (setq a 3)
3
> a
3
> (quote a)
A
> 'a ? ? ? ? ? ? ? ? ? ?;'a is an abbreviation for (quote a)
A
Another similar special form is the function form: function causes its
argument to be interpreted as a function rather than being evaluated.
For example:
另一個(gè)類似的語句是
fuction:function使得解釋器將其參數(shù)視為一個(gè)函數(shù)而不是
解析值,例如:
> (setq + 3)
3
> +
3
> '+
+
> (function +)
#<Function + @ #x-fbef9de>
> #'+ ? ? ? ? ? ? ? ? ? ;#'+ is an abbreviation for (function +)
#<Function + @ #x-fbef9de>
The function special form is useful when you want to pass a function as
an argument to another function. See below for some examples of
functions which take functions as arguments.
當(dāng)我們需要將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)時(shí)會(huì)用到
function 語句。后面
有些示例函數(shù)將函數(shù)作為參數(shù)。
Binding
Binding is lexically scoped assignment. It happens to the variables in
a function's parameter list whenever the function is called: the formal
parameters are bound to the actual parameters for the duration of the
function call. You can bind variables anywhere in a program with the
let special form, which looks like this:
綁定是詞匯作用域賦值(汗,怎么讀怎么別扭--譯者)。每當(dāng)函數(shù)調(diào)用時(shí),它就
發(fā)生于函數(shù)的參數(shù)列變量中:形式參數(shù)被取代為調(diào)用函數(shù)時(shí)的實(shí)際參數(shù)。你可以在
程序中隨處綁定變量,就像下面這樣:
? ? ? ?(let ((var1 val1)
? ? ? ? ? ? ?(var2 val2)
? ? ? ? ? ? ?...)
? ? ? ? ?body)
Let binds var1 to val1, var2 to val2, and so forth; then it executes
the statements in its body. The body of a let follows exactly the same
rules that a function body does. Some examples:
let把val1綁定到var1,把val2綁定到var2,依次類推;然后在它的程序體中執(zhí)
行語句。let的程序體與函數(shù)體的執(zhí)行規(guī)則完全相同。例如:
> (let ((a 3)) (+ a 1))
4
> (let ((a 2)
? ? ? ?(b 3)
? ? ? ?(c 0))
? ?(setq c (+ a b))
? ?c)
5
> (setq c 4)
4
> (let ((c 5)) c)
5
> c
4
Instead of (let ((a nil) (b nil)) ...), you can write (let (a b) ...).
你可以用 (let (a b) ...) 代替 (let ((a nil) (b nil)) ...) 。
The val1, val2, etc. inside a let cannot reference the variables var1,
var2, etc. that the let is binding. For example,
val1,val2等等。在 let 內(nèi)部不能引用
var1,var2等等let正在綁定的成員。
例如(簡(jiǎn)而言之,在參數(shù)表中,形式參數(shù)之間不能互相引用--譯者):
> (let ((x 1)
? ? ? ?(y (+ x 1)))
? ?y)
Error: Attempt to take the value of the unbound symbol X
If the symbol x already has a global value, stranger happenings will
result:
如果符號(hào)x已經(jīng)有了一個(gè)全局值,會(huì)產(chǎn)生一些奇怪的結(jié)果:
> (setq x 7)
7
> (let ((x 1)
? ? ? ?(y (+ x 1)))
? ?y)
8
The let* special form is just like let except that it allows values to
reference variables defined earlier in the let*. For example,
let* 語句類似于 let,但它允許引用之前在 let*
中定義的變量的值。例如:
> (setq x 7)
7
> (let* ((x 1)
? ? ? ? (y (+ x 1)))
? ?y)
2
The form
語句
? ? ? ?(let* ((x a)
? ? ? ? ? ? ? (y b))
? ? ? ? ?...)
is equivalent to
等價(jià)于
? ? ? ?(let ((x a))
? ? ? ? ?(let ((y b))
? ? ? ? ? ?...))
Dynamic Scoping
The let and let* forms provide lexical scoping, which is what you
expect if you're used to programming in C or Pascal. Dynamic scoping is
what you get in BASIC: if you assign a value to a dynamically scoped
variable, every mention of that variable returns that value until you
assign another value to the same variable.
與我們?cè)贑或Pascal中編寫程序不同,let 和 let*
語句提供了詞匯作用域。動(dòng)態(tài)
作用域是我們?cè)贐ASIC里用的那種:如果我們給一個(gè)動(dòng)態(tài)作用域變量賦了值,那么
所有對(duì)這個(gè)變量的訪問都會(huì)取得這個(gè)值,直到給同一個(gè)變量賦了另一個(gè)值為止。
In LISP, dynamically scoped variables are called special variables. You
can declare a special variable with the defvar special form. Here are
some examples of lexically and dynamically scoped variables.
在LISP中,動(dòng)態(tài)作用域變量被稱為特化變量 。你可以用
special 語句 defvar
定義一個(gè)特化變量。這里有一些詞匯化和動(dòng)態(tài)作用域變量的示例。
In this example, the function check-regular references a regular (ie,
lexically scoped) variable. Since check-regular is lexically outside of
the let which binds regular, check-regular returns the variable's
global value.
在以下示例中,check-regular 函數(shù)引用一個(gè) regular
(也就是一個(gè)詞匯作用域)
變量。因?yàn)?check-regular 在綁定 regular 的 let
外部詞匯化,check-regular
返回變量的全局值。
> (setq regular 5)
5
> (defun check-regular () regular)
CHECK-REGULAR
> (check-regular)
5
> (let ((regular 6)) (check-regular))
5
In this example, the function check-special references a special (ie,
dynamically scoped) variable. Since the call to check-special is
temporally inside of the let which binds special, check-special returns
the variable's local value.
在這個(gè)例子中,函數(shù) check-special 引用了一個(gè)
特化(動(dòng)態(tài)作用域)變量。
因此 check-special 調(diào)用臨時(shí)發(fā)生于特化綁定的 let
內(nèi)部,check-special
返回變量的局部值。
> (defvar *special* 5)
*SPECIAL*
> (defun check-special () *special*)
CHECK-SPECIAL
> (check-special)
5
> (let ((*special* 6)) (check-special))
6
By convention, the name of a special variable begins and ends with a *.
Special variables are chiefly used as global variables, since
programmers usually expect lexical scoping for local variables and
dynamic scoping for global variables.
方便起見,特化變量以一個(gè) *
開始和結(jié)束。特化變量主要用于全局變量,因?yàn)?br style="word-wrap:break-word" /> 程序員通常期望局部變量使用詞匯作用域,全局變量使用動(dòng)態(tài)作用域。
For more information on the difference between lexical and dynamic
scoping, see _Common LISP: the Language_.
詞匯和動(dòng)態(tài)作用域的更多差異參見《Common LISP: the
Language》。
Arrays
The function make-array makes an array. The aref function accesses its
elements. All elements of an array are initially set to nil. For
example:
make-array 函數(shù)定義一個(gè)數(shù)組。aref
函數(shù)訪問它的元素。所有元素初始化為nil。
例如:
> (make-array '(3 3))
#2a((NIL NIL NIL) (NIL NIL NIL) (NIL NIL NIL))
> (aref * 1 1)
NIL
> (make-array 4) ? ? ? ?;1D arrays don't need the extra parens
#(NIL NIL NIL NIL)
Array indices always start at 0.
數(shù)組索引從0開始。
See below for how to set the elements of an array.
以后討論如何設(shè)置一個(gè)數(shù)組的元素。
Strings
A string is a sequence of characters between double quotes. LISP
represents a string as a variable-length array of characters. You can
write a string which contains a double quote by preceding the quote
with a backslash; a double backslash stands for a single backslash. For
example:
字符串是包含在雙引號(hào)之間的字符串。LISP
用字符串代表一個(gè)變長(zhǎng)字符數(shù)組。
我們可以用一個(gè)反斜杠加一個(gè)雙引號(hào)來表示字符串中的雙引號(hào),兩個(gè)反斜杠表示
一個(gè)單獨(dú)的反斜杠。例如:
? ? ? ?"abcd" has 4 characters
? ? ? ?"\"" has 1 character
? ? ? ?"\\" has 1 character
Here are some functions for dealing with strings:
有一些函數(shù)可以用于操作字符串:
> (concatenate 'string "abcd" "efg")
"abcdefg"
> (char "abc" 1)
#\b ? ? ? ? ? ? ? ? ? ? ;LISP writes characters preceded by #\
> (aref "abc" 1)
#\b ? ? ? ? ? ? ? ? ? ? ;remember, strings are really arrays
The concatenate function can actually work with any type of sequence:
concatenate 函數(shù)可以用于連接任何類型的序列:
> (concatenate 'string '(#\a #\b) '(#\c))
"abc"
> (concatenate 'list "abc" "de")
(#\a #\b #\c #\d #\e)
> (concatenate 'vector '#(3 3 3) '#(3 3 3))
#(3 3 3 3 3 3)
Structures
LISP structures are analogous to C structs or Pascal records. Here is
an example:
LISP 結(jié)構(gòu)類似于C結(jié)構(gòu)或Pasacal記錄。如下所示:
> (defstruct foo
? ?bar
? ?baaz
? ?quux)
FOO
This example defines a data type called foo which is a structure
containing 3 fields. It also defines 4 functions which operate on this
data type: make-foo, foo-bar, foo-baaz, and foo-quux. The first one
makes a new object of type foo; the others access the fields of an
object of type foo. Here is how to use these functions:
這個(gè)示例定義了一個(gè)名為 foo
的數(shù)據(jù)類型,它是一個(gè)帶有三個(gè)字段的結(jié)構(gòu)。
它同時(shí)定義了4個(gè)函數(shù)用于操作這個(gè)數(shù)據(jù)類型:make-foo,foo-ba,foo-baaz和
foo-quux。第一個(gè)函數(shù)構(gòu)造了一個(gè)foo類型的新對(duì)象,另外三個(gè)用于訪問一個(gè)
foo類型的對(duì)象。以下是這些函數(shù)的用法:
> (make-foo)
#s(FOO :BAR NIL :BAAZ NIL :QUUX NIL)
> (make-foo :baaz 3)
#s(FOO :BAR NIL :BAAZ 3 :QUUX NIL)
> (foo-bar *)
NIL
> (foo-baaz **)
3
The make-foo function can take a keyword argument for each of the
fields a structure of type foo can have. The field access functions
each take one argument, a structure of type foo, and return the
appropriate field.
meke-foo
函數(shù)可以使用foo結(jié)構(gòu)類型的字段作為關(guān)鍵字參數(shù)。字段訪問函數(shù)以
foo類型的結(jié)構(gòu)為參數(shù),返回對(duì)應(yīng)的字段。
See below for how to set the fields of a structure.
以后討論如何設(shè)置一個(gè)結(jié)構(gòu)的字段。
Setf
Certain forms in LISP naturally define a memory location. For example,
if the value of x is a structure of type foo, then (foo-bar x) defines
the bar field of the value of x. Or, if the value of y is a one-
dimensional array, (aref y 2) defines the third element of y.
LISP確認(rèn)語句的時(shí)間,自然就會(huì)定義一個(gè)內(nèi)存區(qū)域。例如,如果x的值是foo類型
的一個(gè)結(jié)構(gòu),(foo-bar
x)定義x中bar字段的值。或者,如果y是一個(gè)一維數(shù)組,
(aref y 2)定義y的第三個(gè)元素。
The setf special form uses its first argument to define a place in
memory, evaluates its second argument, and stores the resulting value
in the resulting memory location. For example,
setf
語句用于在內(nèi)存中將它的第一個(gè)參數(shù)定位到第二個(gè)參數(shù)上,并且返回內(nèi)存
區(qū)域的結(jié)果值。例如:
> (setq a (make-array 3))
#(NIL NIL NIL)
> (aref a 1)
NIL
> (setf (aref a 1) 3)
3
> a
#(NIL 3 NIL)
> (aref a 1)
3
> (defstruct foo bar)
FOO
> (setq a (make-foo))
#s(FOO :BAR NIL)
> (foo-bar a)
NIL
> (setf (foo-bar a) 3)
3
> a
#s(FOO :BAR 3)
> (foo-bar a)
3
Setf is the only way to set the fields of a structure or the elements
of an array.
setf是給結(jié)構(gòu)的字段或者數(shù)組的元素賦值的唯一方法。
Here are some more examples of setf and related functions.
這里還有一些關(guān)于setf和相關(guān)函數(shù)的示例。
> (setf a (make-array 1)) ? ? ? ;setf on a variable is equivalent to setq
#(NIL)
> (push 5 (aref a 1)) ? ? ? ? ? ;push can act like setf
(5)
> (pop (aref a 1)) ? ? ? ? ? ? ?;so can pop
5
> (setf (aref a 1) 5)
5
> (incf (aref a 1)) ? ? ? ? ? ? ;incf reads from a place, increments,
6 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;and writes back
> (aref a 1)
6
Booleans and Conditionals
LISP uses the self-evaluating symbol nil to mean false. Anything other
than nil means true. Unless we have a reason not to, we usually use the
self-evaluating symbol t to stand for true.
LISP 用自解析符號(hào) nil 來代表 false。任何 nil
之外的其它東西都代表 true。
除非有什么特別的原因,我們總是使用 true
的標(biāo)準(zhǔn)自解析符號(hào) t。
LISP provides a standard set of logical functions, for example and, or,
and not. The and and or connectives are short-circuiting: and will not
evaluate any arguments to the right of the first one which evaluates to
nil, while or will not evaluate any arguments to the right of the first
one which evaluates to t.
LISP提供了一個(gè)邏輯運(yùn)算的標(biāo)準(zhǔn)函數(shù)集,例如,與、或、非。與和或支持短路算法:
在遇到第一個(gè)nil后不再解析右面的參數(shù),而與在遇到第一個(gè)t后也不再解析右面的
參數(shù)。
LISP also provides several special forms for conditional execution. The
simplest of these is if. The first argument of if determines whether
the second or third argument will be executed:
LISP還為條件控制提供了幾個(gè)特殊語句。最簡(jiǎn)單的是if。if語句的第一個(gè)參數(shù)決定了
執(zhí)行第二或第三個(gè)參數(shù)中的哪一個(gè):
> (if t 5 6)
5
> (if nil 5 6)
6
> (if 4 5 6)
5
If you need to put more than one statement in the then or else clause
of an if statement, you can use the progn special form. Progn executes
each statement in its body, then returns the value of the final one.
如果你需要在then或else塊中放置超過一行的語句,可以使用特殊語句
progn。
Progn
在它的程序體內(nèi)依次執(zhí)行每一條語句,返回最后一個(gè)結(jié)果。
> (setq a 7)
7
> (setq b 0)
0
> (setq c 5)
5
> (if (> a 5)
? ?(progn
? ? ?(setq a (+ b 7))
? ? ?(setq b (+ c 8)))
? ?(setq b 4))
13
An if statement which lacks either a then or an else clause can be
written using the when or unless special form:
一個(gè)沒有 else 或 when 的語句可以寫為 when 或 unless
語句。
> (when t 3)
3
> (when nil 3)
NIL
> (unless t 3)
NIL
> (unless nil 3)
3
When and unless, unlike if, allow any number of statements in their
bodies. (Eg, (when x a b c) is equivalent to (if x (progn a b c)).)
與 if 不同,when 和 unless
允許在程序體內(nèi)放置任意多的語句。(例如,
(when x a b c) 等價(jià)于 (if x (progn a b c)))
> (when t
? ?(setq a 5)
? ?(+ a 6))
11
More complicated conditionals can be defined using the cond special
form, which is equivalent to an if ... else if ... fi construction.
更復(fù)雜的條件控制可以用 cond
語句定義實(shí)現(xiàn),它定價(jià)于一個(gè) if ... else
if ... fi 條件。
A cond consists of the symbol cond followed by a number of cond
clauses, each of which is a list. The first element of a cond clause is
the condition; the remaining elements (if any) are the action. The cond
form finds the first clause whose condition evaluates to true (ie,
doesn't evaluate to nil); it then executes the corresponding action and
returns the resulting value. None of the remaining conditions are
evaluated; nor are any actions except the one corresponding to the
selected condition. For example:
一個(gè) cond 由 symbol
符號(hào)和其后的若干條件分支組成,每一個(gè)分支是一個(gè)
list。
cond
分支的第一個(gè)元素是條件;其它的元素(如果有的話)是動(dòng)作。cond語句查
找第一個(gè)條件解析為 true
的分支,執(zhí)行其響應(yīng)動(dòng)作并返回結(jié)果值。其它條件不會(huì)
被解析,除了這個(gè)響應(yīng)之外的分支也不會(huì)執(zhí)行。例如:
> (setq a 3)
3
> (cond
? ((evenp a) a) ? ? ? ?;if a is even return a
? ((> a 7) (/ a 2)) ? ?;else if a is bigger than 7 return a/2
? ((< a 5) (- a 1)) ? ?;else if a is smaller than 5 return a-1
? (t 17)) ? ? ? ? ? ? ?;else return 17
2
If the action in the selected cond clause is missing, cond returns what
the condition evaluated to:
如果選定的分支沒有響應(yīng)動(dòng)作,cond
返回條件的解析結(jié)果。
> (cond ((+ 3 4)))
7
Here's a clever little recursive function which uses cond. You might be
interested in trying to prove that it terminates for all integers x at
least 1. (If you succeed, please publish the result.)
這里用 cond
巧妙的實(shí)現(xiàn)了一個(gè)遞歸函數(shù)。你可能會(huì)有興趣證明它對(duì)于所有的整數(shù)
x 都少有個(gè)終結(jié)。(如果你成功了,請(qǐng)發(fā)表出來。)
> (defun hotpo (x steps) ? ? ? ?;hotpo stands for Half Or Triple Plus One
? ?(cond
? ? ((= x 1) steps)
? ? ((oddp x) (hotpo (+ 1 (* x 3)) (+ 1 steps)))
? ? (t (hotpo (/ x 2) (+ 1 steps)))))
A
> (hotpo 7 0)
16
The LISP case statement is like a C switch statement:
LISP 的 case 語句類似于 C 的 switch 語句:
> (setq x 'b)
B
> (case x
? (a 5)
? ((d e) 7)
? ((b f) 3)
? (otherwise 9))
3
The otherwise clause at the end means that if x is not a, b, d, e, or
f, the case statement will return 9.
末尾的 otherwise 語句意味著 x
不是a、b、c、d、e、f,case語句將會(huì)返回9。
Iteration
The simplest iteration construct in LISP is loop: a loop construct
repeatedly executes its body until it hits a return special form. For
example,
LISP 中最簡(jiǎn)單的迭代結(jié)構(gòu)是 loop:loop
結(jié)構(gòu)反復(fù)執(zhí)行它的程序體直到到達(dá)
一個(gè)返回語句,例如:
> (setq a 4)
4
> (loop
? (setq a (+ a 1))
? (when (> a 7) (return a)))
8
> (loop
? (setq a (- a 1))
? (when (< a 3) (return)))
NIL
The next simplest is dolist: dolist binds a variable to the elements of
a list in order and stops when it hits the end of the list.
dolist是下一個(gè)最簡(jiǎn)單的:dolist把一個(gè)變量依次綁定到一個(gè)列表的各個(gè)元素上,
在到達(dá)列表結(jié)尾時(shí)結(jié)束。
> (dolist (x '(a b c)) (print x))
A
B
C
NIL
Dolist always returns nil. Note that the value of x in the above
example was never nil: the NIL below the C was the value that dolist
returned, printed by the read-eval-print loop.
Dolist 總是返回nil。注意上例中的 x
永遠(yuǎn)不會(huì)為nil:C后面的NIL是dolist
返回的,它被讀取-解析-打印循環(huán)所打印。
The most complicated iteration primitive is called do. A do statement
looks like this:
更復(fù)雜的迭代稱為 do。do語句的示例如下:
> (do ((x 1 (+ x 1))
? ? ? (y 1 (* y 2)))
? ? ?((> x 5) y)
? ?(print y)
? ?(print 'working))
1
WORKING
2
WORKING
4
WORKING
8
WORKING
16
WORKING
32
The first part of a do specifies what variables to bind, what their
initial values are, and how to update them. The second part specifies a
termination condition and a return value. The last part is the body. A
do form binds its variables to their initial values like a let, then
checks the termination condition. As long as the condition is false, it
executes the body repeatedly; when the condition becomes true, it
returns the value of the return-value form.
do的第一步是指定綁定的變量,它們的初始值,以及如何更新。第二步是指定一
個(gè)終止條件和返回值。最后是程序體。do語句像let一樣把它的變量綁定到初始值,
然后校驗(yàn)終止條件。條件為false時(shí),它重復(fù)執(zhí)行程序體;當(dāng)條件為true,它返回
return-value 語句的值。
The do* form is to do as let* is to let.
do* 語句之于 do 如同 let* 之于 let。
Non-local Exits
The return special form mentioned in the section on iteration is an
example of a nonlocal return. Another example is the return-from form,
which returns a value from the surrounding function:
前一節(jié)中迭代示例里的renturn語句是一個(gè)無定位返回的示例,另一個(gè)是
return-from,它從包圍它的函數(shù)中返回指定值。
> (defun foo (x)
? ?(return-from foo 3)
? ?x)
FOO
> (foo 17)
3
Actually, the return-from form can return from any named block -- it's
just that functions are the only blocks which are named by default. You
can create a named block with the block special form:
實(shí)際上,return-from
語句可以從任何已命名的語句塊中退出--只是默認(rèn)情況下
函數(shù)是唯一的命名語句塊而已。我們可以用 block
語句自己定義一個(gè)命名語句塊。
> (block foo
? ?(return-from foo 7)
? ?3)
7
The return special form can return from any block named nil. Loops are
by default labelled nil, but you can make your own nil-labelled blocks:
return
語句可以從任何nil命名的語句塊中返回。默認(rèn)情況下循環(huán)是nil命名,而
我們可以創(chuàng)建自己的nil標(biāo)記語句塊。
> (block nil
? ?(return 7)
? ?3)
7
Another form which causes a nonlocal exit is the error form:
另外一個(gè)無定位退出語句是 error 語句:
> (error "This is an error")
Error: This is an error
The error form applies format to its arguments, then places you in the
debugger.
error語句格式化它的參數(shù),然后進(jìn)入調(diào)試器。
Funcall, Apply, and Mapcar
Earlier I promised to give some functions which take functions as
arguments. Here they are:
早先我承諾介紹一些可以將函數(shù)作為參數(shù)調(diào)用函數(shù),它們?cè)谶@里:
> (funcall #'+ 3 4)
7
> (apply #'+ 3 4 '(3 4))
14
> (mapcar #'not '(t nil t nil t nil))
(NIL T NIL T NIL T)
Funcall calls its first argument on its remaining arguments.
funcall 用它的其它參數(shù)調(diào)用它的第一個(gè)參數(shù)。
Apply is just like funcall, except that its final argument should be a
list; the elements of that list are treated as if they were additional
arguments to a funcall.
Apply和funcall很相像,不過它的最后一個(gè)參數(shù)可以是一個(gè)列表;這個(gè)列表被看
作是funcall的附加參數(shù)。
The first argument to mapcar must be a function of one argument; mapcar
applies this function to each element of a list and collects the
results in another list.
mapcar的第一個(gè)參數(shù)必須是一個(gè)單參數(shù)的函數(shù);mapcar在列表上逐個(gè)元素應(yīng)用該
函數(shù),并將返回值包含如另一個(gè)鏈表。
Funcall and apply are chiefly useful when their first argument is a
variable. For instance, a search engine could take a heuristic function
as a parameter and use funcall or apply to call that function on a
state description. The sorting functions described later use funcall
to call their comparison functions.
Funcall和apply主要用于第一個(gè)參數(shù)是變量的場(chǎng)合。例如,搜索引擎把一個(gè)啟發(fā)式
函數(shù)作為參數(shù),在一個(gè)狀態(tài)描述上應(yīng)用funcall或者apply。
Mapcar, along with nameless functions (see below), can replace many
loops.
Mapcar配合匿名函數(shù)(后面介紹),可以取代很多循環(huán)。
Lambda
If you just want to create a temporary function and don't want to
bother giving it a name, lambda is what you need.
如果你只是想創(chuàng)建一個(gè)臨時(shí)函數(shù),并不想給它一個(gè)命名,lambda如你所愿。
> #'(lambda (x) (+ x 3))
(LAMBDA (X) (+ X 3))
> (funcall * 5)
8
The combination of lambda and mapcar can replace many loops. For
example, the following two forms are equivalent:
lambda和mapcar的組合可以取代很多循環(huán),例如,如下的兩個(gè)語句是等價(jià)的:
> (do ((x '(1 2 3 4 5) (cdr x))
? ? ? (y nil))
? ? ?((null x) (reverse y))
? ?(push (+ (car x) 2) y))
(3 4 5 6 7)
> (mapcar #'(lambda (x) (+ x 2)) '(1 2 3 4 5))
(3 4 5 6 7)
Sorting
LISP provides two primitives for sorting: sort and stable-sort.
LISP提供兩種主要的排序:排序和穩(wěn)定排序。
> (sort '(2 1 5 4 6) #'<)
(1 2 4 5 6)
> (sort '(2 1 5 4 6) #'>)
(6 5 4 2 1)
The first argument to sort is a list; the second is a comparison
function. The sort function does not guarantee stability: if there are
two elements a and b such that (and (not (< a b)) (not (< b a))), sort
may arrange them in either order. The stable-sort function is exactly
like sort, except that it guarantees that two equivalent elements
appear in the sorted list in the same order that they appeared in the
original list.
sort的第一個(gè)參數(shù)是一個(gè)列表,第二個(gè)是一個(gè)比較函數(shù)。sort函數(shù)不保證穩(wěn)定性:
如果這里有a和b兩個(gè)元素,(and (not (< a b)) (not (< b
a))),sort可能會(huì)改
變它們的位置。stable-sort(穩(wěn)定排序)與sort非常像,不過它確保兩個(gè)相等
的元素在排序后的列表中的順序與排序前列表中的順序相同。
Be careful: sort is allowed to destroy its argument, so if the original
sequence is important to you, make a copy with the copy-list or
copy-seq
function.
注意:sort可能會(huì)破壞它的參數(shù),如果原始序列對(duì)我們很重要,最好使用copy-list
或copy-seq函數(shù)創(chuàng)建一個(gè)副本。
Equality
LISP has many different ideas of equality. Numerical equality is
denoted by =. Two symbols are eq if and only if they are identical. Two
copies of the same list are not eq, but they are equal.
關(guān)于相等,LISP有很多不同的觀點(diǎn)。數(shù)值相等意味著=。兩個(gè)符號(hào)當(dāng)且僅當(dāng)他們完全
一樣時(shí)相同。同一個(gè)列表的兩個(gè)副本不相同,但是它們相等。
> (eq 'a 'a)
T
> (eq 'a 'b)
NIL
> (= 3 4)
NIL
> (eq '(a b c) '(a b c))
NIL
> (equal '(a b c) '(a b c))
T
> (eql 'a 'a)
T
> (eql 3 3)
T
The eql predicate is equivalent to eq for symbols and to = for numbers
or the same type:
謂詞eql代表相等,它對(duì)于符號(hào)表示相同,對(duì)于數(shù)值表示=。
> (eql 2.0 2)
NIL
> (= 2.0 2)
T
> (eq 12345678901234567890 12345678901234567890)
NIL
> (= 12345678901234567890 12345678901234567890)
T
> (eql 12345678901234567890 12345678901234567890)
T
The equal predicate is equivalent to eql for symbols and numbers. It is
true for two conses if and only if their cars are equal and their cdrs
are equal. It is true for two structures if and only if the structures
are the same type and their corresponding fields are equal.
equal謂詞對(duì)于符號(hào)和數(shù)值是相等。當(dāng)且僅當(dāng)兩個(gè) conse
的car和cdr都相等時(shí)它們
才是相等的。當(dāng)且僅當(dāng)兩個(gè)結(jié)構(gòu)是同類型而且各字段都相等時(shí)它們相等。
Some Useful List Functions
These functions all manipulate lists.
這些函數(shù)都用來操作列表。
> (append '(1 2 3) '(4 5 6)) ? ?;concatenate lists
(1 2 3 4 5 6)
> (reverse '(1 2 3)) ? ? ? ? ? ?;reverse the elements of a list
(3 2 1)
> (member 'a '(b d a c)) ? ? ? ?;set membership -- returns the first tail
(A C) ? ? ? ? ? ? ? ? ? ? ? ? ? ;whose car is the desired element
> (find 'a '(b d a c)) ? ? ? ? ?;another way to do set membership
A
> (find '(a b) '((a d) (a d e) (a b d e) ()) :test #'subsetp)
(A B D E) ? ? ? ? ? ? ? ? ? ? ? ;find is more flexible though
> (subsetp '(a b) '(a d e)) ? ? ;set containment
NIL
> (intersection '(a b c) '(b)) ?;set intersection
(B)
> (union '(a) '(b)) ? ? ? ? ? ? ;set union
(A B)
> (set-difference '(a b) '(a)) ?;set difference
(B)
Subsetp, intersection, union, and set-difference all assume that each
argument contains no duplicate elements -- (subsetp '(a a) '(a b b)) is
allowed to fail, for example.
Subsetp,intersection,union和set-difference都允許各個(gè)參數(shù)包含不匹配的元素
--例如,(subsetp '(a a) '(a b b))可以為fail。
Find, subsetp, intersection, union, and set-difference can all take a
:test keyword argument; by default, they all use eql.
Find,subsetp,intersection,union和set-difference都可以接受一個(gè):test關(guān)鍵
字參數(shù);默認(rèn)情況下,它們是等價(jià)的。
Getting Started with Emacs
You can use Emacs to edit LISP code: most Emacses are set up to enter
LISP mode automatically when they find a file which ends in .lisp, but
if yours isn't, you can type M-x lisp-mode.
你可以使用Emacs編輯LISP代碼:Emaces在打開.lisp文件時(shí)總會(huì)自動(dòng)進(jìn)入LISP模式,
不過如果我們的Emacs沒有成功進(jìn)入這個(gè)狀態(tài),可以通過輸入M-x
lisp-mode做到。
You can run LISP under Emacs, too: make sure that there is a command in
your path called "lisp" which runs your favorite LISP. For example, you
could type
我們也可以在Emacs下運(yùn)行LISP:先確保在我們的私人路徑下可以運(yùn)行一個(gè)叫
"LISP"的命令。例如,我們可以輸入:
? ? ? ?ln -s /usr/local/bin/clisp ~/bin/lisp
Then in Emacs type M-x run-lisp. You can send LISP code to the LISP you
just started, and do all sorts of other cool things; for more
information, type C-h m from any buffer which is in LISP mode.
然后在Emacs中輸入 M-x
run-lip。我們可以向LISP發(fā)送先前的LISP代碼,做其它
很酷的事情;在LISP模式下的任何緩沖輸入 C-h
m可以得到進(jìn)一步的信息。
Actually, you don't even need to make a link. Emacs has a variable
called inferior-lisp-program; so if you add the line
實(shí)際上,我們甚至不需要建立鏈接。Emacs有一個(gè)變量叫
inferior-lisp-program;
所以我們可以把下面這行
? ? ? ?(setq inferior-lisp-program "/usr/local/bin/clisp")
to your .emacs file, Emacs will know where to find CLISP when
you type M-x run-lisp.
輸入到自己的 .emacs 文件中,Emacs就會(huì)知道在你輸入 M-x
run-lisp時(shí)去哪里尋找
CLISP。
? ? ? ? ? ? ? ? ? ? ? ? ?Geoffrey J. Gordon
? ? ? ? ? ? ? ? ? ? ? ? < ggordon@cs.cmu.edu >
? ? ? ? ? ? ? ? ? ? ? Friday, February 5, 1993
? ? ? ? ? ? ? ? ? ? ? ? ? ?Modified by
? ? ? ? ? ? ? ? ? ? ? ? ? ?Bruno Haible
? ? ? ? ? ? ? ?< haible@ma2s2.mathematik.uni-karlsruhe.de >
? ? ? ? ? ? ? ? ? ? ? ? ? 簡(jiǎn)體中文版翻譯:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?劉鑫
? ? ? ? ? ? ? ? ? ? ? ?< March.Liu@gmail.com >
Note: This tutorial introduction to Common Lisp was written for the
CMU environment, so some of the details of running lisp toward the end
may differ from site to site.
注意:這份 Common Lisp 入門教程是針對(duì) CMU
環(huán)境編寫,所以在其它環(huán)境運(yùn)行
LISP時(shí)可能會(huì)有細(xì)節(jié)上的區(qū)別。
Further Information
附:
The best LISP textbook I know of is
?Guy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984.
據(jù)我所知最好的 Lisp 書籍是:
?Guy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984.
The first edition is easier to read; the second describes a more recent
standard. (The differences between the two standards shouldn't affect
casual programmers.)
第一版很容易閱讀,第二版介紹了更新的標(biāo)準(zhǔn)。(兩個(gè)標(biāo)準(zhǔn)的差異很 小,對(duì)于粗
心的程序員沒有什么區(qū)別。)
A book by Dave Touretsky has also been recommended to me, although I
haven't read it, so I can't say anything about it.
我還記得 Dave Touretsky
寫了一本,不過我從來沒讀過,所以不能對(duì)那本書
發(fā)表評(píng)論。
Symbols
符號(hào)
A symbol is just a string of characters. There are restrictions on what
you can include in a symbol and what the first character can be, but as
long as you stick to letters, digits, and hyphens, you'll be safe.
(Except that if you use only digits and possibly an initial hyphen,
LISP will think you typed an integer rather than a symbol.) Some
examples of symbols:
符號(hào)僅僅是字符串。你可以在符號(hào)中包含字母、數(shù)字、連接符等等,唯一的限制就
是要以字母開頭。(如果你只輸入數(shù)字,最多再以一個(gè)連接符開頭的話,LISP會(huì)認(rèn)
為你輸入了一個(gè)整數(shù)而不是符號(hào)。)例如:
? ? ? ?a
? ? ? ?b
? ? ? ?c1
? ? ? ?foo
? ? ? ?bar
? ? ? ?baaz-quux-garply
Some things you can do with symbols follow. (Things after a ">" prompt
are what you type to the LISP interpreter, while other things are what
the LISP interpreter prints back to you. The ";" is LISP's comment
character: everything from a ";" to the end of line is ignored.)
接下來我們可以做些事情。(">"標(biāo)記表示你向LISP輸入的東西,其它的是LISP
打印返回給你的。";"是LISP的注釋符:";"后面的整行都會(huì)被忽略。)
> (setq a 5) ? ? ? ? ? ?;store a number as the value of a symbol
5
> a ? ? ? ? ? ? ? ? ? ? ;take the value of a symbol
5
> (let ((a 6)) a) ? ? ? ;bind the value of a symbol temporarily to 6
6
> a ? ? ? ? ? ? ? ? ? ? ;the value returns to 5 once the let is finished
5
> (+ a 6) ? ? ? ? ? ? ? ;use the value of a symbol as an argument to a function
11
> b ? ? ? ? ? ? ? ? ? ? ;try to take the value of a symbol which has no value
Error: Attempt to take the value of the unbound symbol B
There are two special symbols, t and nil. The value of t is defined
always to be t, and the value of nil is defined always to be nil. LISP
uses t and nil to represent true and false. An example of this use is
in the if statement, described more fully later:
有兩個(gè)特殊的符號(hào), t 和 nil 。 t 的值總是定義為 t
,nil 的值總是定義為
nil 。LISP用 t 和 nil 代表 true 和
false。以下是使用這個(gè)功能的 if 語句
,后面再做詳細(xì)說明:
> (if t 5 6)
5
> (if nil 5 6)
6
> (if 4 5 6)
5
The last example is odd but correct: nil means false, and anything else
means true. (Unless we have a reason to do otherwise, we use t to mean
true, just for the sake of clarity.)
最后一個(gè)例子看起來很怪,但是沒有錯(cuò):nil 代表 false
,其它任意值代表 true。
(為了代碼清晰,在沒有什么特別原因的情況下,我們用t代表true。)
Symbols like t and nil are called self-evaluating symbols, because
they evaluate to themselves. There is a whole class of self-evaluating
symbols called keywords; any symbol whose name starts with a colon is a
keyword. (See below for some uses for keywords.) Some examples:
t 和 nil
這樣的符號(hào)被稱為自解析符號(hào),因?yàn)樗麄兘馕鰹樽陨怼W越馕龇?hào)稱為
關(guān)鍵字;任一以冒號(hào)開頭的符號(hào)都是關(guān)鍵字。(下面是一些關(guān)鍵字的應(yīng)用)如下
所示:
> :this-is-a-keyword
:THIS-IS-A-KEYWORD
> :so-is-this
:SO-IS-THIS
> :me-too
:ME-TOO
Numbers
數(shù)值
An integer is a string of digits optionally preceded by + or -. A real
number looks like an integer, except that it has a decimal point and
optionally can be written in scientific notation. A rational looks like
two integers with a / between them. LISP supports complex numbers,
which are written #c(r i) (where r is the real part and i is the
imaginary part). A number is any of the above. Here are some numbers:
數(shù)值類型是數(shù)字文本,可能會(huì)以 + 或 -
開頭。實(shí)數(shù)和整數(shù)很相像,但是它帶有
小數(shù)點(diǎn),還可能寫成科學(xué)計(jì)數(shù)法。有理數(shù)就像是兩個(gè)整數(shù)之間帶有一個(gè)/。LISP支
持復(fù)數(shù),寫為#c(r
i)(r表示實(shí)部,i表示虛部)。以上統(tǒng)稱為數(shù)值。下面是一
些數(shù)值:
? ? ? ?5
? ? ? ?17
? ? ? ?-34
? ? ? ?+6
? ? ? ?3.1415
? ? ? ?1.722e-15
? ? ? ?#c(1.722e-15 0.75)
The standard arithmetic functions are all available: +, -, *, /, floor,
ceiling, mod, sin, cos, tan, sqrt, exp, expt, and so forth. All of them
accept any kind of number as an argument. +, -, *, and / return a
number according to type contagion: an integer plus a rational is a
rational, a rational plus a real is a real, and a real plus a complex
is a complex. Here are some examples:
標(biāo)準(zhǔn)的計(jì)算函數(shù)包括: +, -, *, /, floor, ceiling, mod, sin,
cos, tan,
sqrt, exp, expt
等等。所有這些函數(shù)都可以接受任意數(shù)值類型參數(shù)。+、-、*
和
/返回盡可能大的類型:一個(gè)整數(shù)加一個(gè)有理數(shù)返回有理數(shù),一個(gè)有理數(shù)加一個(gè)實(shí)數(shù)
是一個(gè)實(shí)數(shù),一個(gè)實(shí)數(shù)加一個(gè)復(fù)數(shù)是一個(gè)復(fù)數(shù)。如下所示:
> (+ 3 3/4) ? ? ? ? ? ? ;type contagion
15/4
> (exp 1) ? ? ? ? ? ? ? ;e
2.7182817
> (exp 3) ? ? ? ? ? ? ? ;e*e*e
20.085537
> (expt 3 4.2) ? ? ? ? ?;exponent with a base other than e
100.90418
> (+ 5 6 7 (* 8 9 10)) ?;the fns +-*/ all accept multiple arguments
There is no limit to the absolute value of an integer except the memory
size of your computer. Be warned that computations with bignums (as
large integers are called) can be slow. (So can computations with
rationals, especially compared to the corresponding computations with
small integers or floats.)
對(duì)于整數(shù)來說,唯一的大小限制就是機(jī)器的內(nèi)存。當(dāng)然大數(shù)值運(yùn)算(這
會(huì)調(diào)用大整數(shù))可能會(huì)很慢。(因此我們可以計(jì)算有理數(shù),尤其是小整數(shù)和浮點(diǎn)數(shù)
的比較運(yùn)算)
Conses
A cons is just a two-field record. The fields are called "car" and
"cdr", for historical reasons. (On the first machine where LISP was
implemented, there were two instructions CAR and CDR which stood for
"contents of address register" and "contents of decrement register".
Conses were implemented using these two registers.)
cons
就是一個(gè)包含兩個(gè)字段的記錄。出于歷史原因,兩個(gè)字段分別被稱為
"car"和"cdr"。(在第一臺(tái)實(shí)現(xiàn)LISP的機(jī)器上,用CAR和CDR代表"地址寄
存器的內(nèi)容"和"指令寄存器的內(nèi)容"。Conses的實(shí)現(xiàn)主要依靠這兩個(gè)寄存器。)
Conses are easy to use:
Conses很容易使用:
> (cons 4 5) ? ? ? ? ? ?;Allocate a cons. Set the car to 4 and the cdr to 5.
(4 . 5)
> (cons (cons 4 5) 6)
((4 . 5) . 6)
> (car (cons 4 5))
4
> (cdr (cons 4 5))
5
Lists
You can build many structures out of conses. Perhaps the simplest is a
linked list: the car of each cons points to one of the elements of the
list, and the cdr points either to another cons or to nil. You can
create such a linked list with the list fuction:
你可以構(gòu)造conses之外的結(jié)構(gòu)。可能最簡(jiǎn)單的是鏈表:每一個(gè)cons的car指向鏈表
的一個(gè)元素,cdr指向另一個(gè)cons或者nil。我們可以使用list函數(shù)構(gòu)造鏈表。
> (list 4 5 6)
(4 5 6)
Notice that LISP prints linked lists a special way: it omits some of
the periods and parentheses. The rule is: if the cdr of a cons is nil,
LISP doesn't bother to print the period or the nil; and if the cdr of
cons A is cons B, then LISP doesn't bother to print the period for cons
A or the parentheses for cons B. So:
需要注意的是 LISP
用一種特殊的方式打印鏈表:它忽略掉某些分隔和括號(hào)。
規(guī)則如下:如果某個(gè) cons 的 cdr 是 nil ,LISP 不打印 nil
和段標(biāo)記,如果
cons A 的 cdr 是 cons B,LISP不打印 cons B 的括號(hào)和 cons A
的分隔符。
如下:
> (cons 4 nil)
(4)
> (cons 4 (cons 5 6))
(4 5 . 6)
> (cons 4 (cons 5 (cons 6 nil)))
(4 5 6)
The last example is exactly equivalent to the call (list 4 5 6). Note
that nil now means the list with no elements: the cdr of (a b), a list
with 2 elements, is (b), a list with 1 element; and the cdr of (b), a
list with 1 element, is nil, which therefore must be a list with no
elements.
最后一個(gè)例子相當(dāng)于調(diào)用(list 4 5 6)。要注意的是這里
nil 表示沒有元素的空
鏈表:包含兩個(gè)元素的鏈表(a
b)中,cdr是(b),一個(gè)含有單個(gè)元素的鏈表;包含
一個(gè)元素的鏈表(b),cdr是nil,故此這里必然是一個(gè)沒有元素的鏈表。
The car and cdr of nil are defined to be nil.
nil 的 car 和 cdr 定義為nil。
If you store your list in a variable, you can make it act like a stack:
如果你把鏈表存儲(chǔ)在變量中,可以將它當(dāng)作堆棧來使用:
> (setq a nil)
NIL
> (push 4 a)
(4)
> (push 5 a)
(5 4)
> (pop a)
5
> a
(4)
> (pop a)
4
> (pop a)
NIL
> a
NIL
Functions
You saw one example of a function above. Here are some more:
前面我們討論過一些函數(shù)的例子,這里還有更多:
> (+ 3 4 5 6) ? ? ? ? ? ? ? ? ? ;this function takes any number of arguments
18
> (+ (+ 3 4) (+ (+ 4 5) 6)) ? ? ;isn't prefix notation fun?
22
> (defun foo (x y) (+ x y 5)) ? ;defining a function
FOO
> (foo 5 0) ? ? ? ? ? ? ? ? ? ? ;calling a function
10
> (defun fact (x) ? ? ? ? ? ? ? ;a recursive function
? ?(if (> x 0)
? ? ?(* x (fact (- x 1)))
? ? ?1))
FACT
> (fact 5)
120
> (defun a (x) (if (= x 0) t (b (- x)))) ? ? ? ?;mutually recursive functions
A
> (defun b (x) (if (> x 0) (a (- x 1)) (a (+ x 1))))
B
> (a 5)
T
> (defun bar (x) ? ? ? ? ? ? ? ?;a function with multiple statements in
? ?(setq x (* x 3)) ? ? ? ? ? ?;its body -- it will return the value
? ?(setq x (/ x 2)) ? ? ? ? ? ?;returned by its final statement
? ?(+ x 4))
BAR
> (bar 6)
13
When we defined foo, we gave it two arguments, x and y. Now when we
call foo, we are required to provide exactly two arguments: the first
will become the value of x for the duration of the call to foo, and the
second will become the value of y for the duration of the call. In
LISP, most variables are lexically scoped; that is, if foo calls bar
and bar tries to reference x, bar will not get foo's value for x.
當(dāng)我們定義函數(shù)的時(shí)候,設(shè)定了兩個(gè)參數(shù),x 和
y。現(xiàn)在當(dāng)我們調(diào)用 foo,需要
給出兩個(gè)參數(shù):第一個(gè)在 foo 函數(shù)調(diào)用時(shí)成為 x
的值,第二個(gè)成為 y 的值。
在LISP中,大部分的變量都是局部的,如果 foo 調(diào)用了
bar ,bar中雖然使用了
名字為x的引用,但bar 得不到 foo 中的 x 。
The process of assigning a symbol a value for the duration of some
lexical scope is called binding.
在調(diào)用過程中給一個(gè)符號(hào)賦值的操作被稱為綁定。
You can specify optional arguments for your functions. Any argument
after the symbol &optional is optional:
我們可以給函數(shù)指定可選參數(shù),在符號(hào)&optional
之后的參數(shù)是可選參數(shù):
> (defun bar (x &optional y) (if y x 0))
BAR
> (defun baaz (&optional (x 3) (z 10)) (+ x z))
BAAZ
> (bar 5)
0
> (bar 5 t)
5
> (baaz 5)
15
> (baaz 5 6)
11
> (baaz)
13
It is legal to call the function bar with either one or two arguments.
If it is called with one argument, x will be bound to the value of that
argument and y will be bound to nil; if it is called with two
arguments, x and y will be bound to the values of the first and second
argument, respectively.
bar函數(shù)的調(diào)用規(guī)則是要給出一個(gè)或兩個(gè)參數(shù)。如果它用一個(gè)參數(shù)調(diào)用,x
將會(huì)綁
定到這個(gè)參數(shù)值上,而 y 就是
nil;如果用兩個(gè)參數(shù)調(diào)用它,x和y會(huì)分別綁定
到第一和第二個(gè)值上。
The function baaz has two optional arguments. It specifies a default
value for each of them: if the caller specifies only one argument, z
will be bound to 10 instead of to nil, and if the caller specifies no
arguments, x will be bound to 3 and z to 10.
baaz
函數(shù)有兩個(gè)可選參數(shù)。它為它們分別提供了默認(rèn)值:如果調(diào)用者只給出了一
個(gè)參數(shù),z會(huì)綁定為10而不是nil,如果調(diào)用者沒有給出參數(shù),x會(huì)綁定為3,而z綁
定為10。
You can make your function accept any number of arguments by ending its
argument list with an &rest parameter. LISP will collect all arguments
not otherwise accounted for into a list and bind the &rest parameter to
that list. So:
在參數(shù)列表的最后設(shè)置一個(gè) &rest
參數(shù),可以使我們的函數(shù)接受任意數(shù)目的參數(shù)。
LISP把所有的附加參數(shù)都放進(jìn)一個(gè)鏈表并綁定到 &rest
參數(shù)。如下:
> (defun foo (x &rest y) y)
FOO
> (foo 3)
NIL
> (foo 4 5 6)
(5 6)
Finally, you can give your function another kind of optional argument
called a keyword argument. The caller can give these arguments in any
order, because they're labelled with keywords.
最后,我們可以為函數(shù)指定一種被稱為關(guān)鍵字參數(shù)的可選參數(shù)。調(diào)用者可以用
任意順序調(diào)用這些參數(shù),因?yàn)樗麄円呀?jīng)通過關(guān)鍵字標(biāo)示出來。
> (defun foo (&key x y) (cons x y))
FOO
> (foo :x 5 :y 3)
(5 . 3)
> (foo :y 3 :x 5)
(5 . 3)
> (foo :y 3)
(NIL . 3)
> (foo)
(NIL)
An &key parameter can have a default value too:
關(guān)鍵字參數(shù)也可以有默認(rèn)值:
> (defun foo (&key (x 5)) x)
FOO
> (foo :x 7)
7
> (foo)
5
Printing
Some functions can cause output. The simplest one is print, which
prints its argument and then returns it.
某些函數(shù)可以用來輸出。最簡(jiǎn)單的一個(gè)是
print,它可以打印參數(shù)并且返回
它們。
> (print 3)
3
3
The first 3 above was printed, the second was returned.
首先打印3,然后返回它。
If you want more complicated output, you will need to use format.
Here's an example:
如果你需要更復(fù)雜的輸出,可能會(huì)用到
format,這里有個(gè)例子:
> (format t "An atom: ~S~%and a list: ~S~%and an integer: ~D~%"
? ? ? ? ?nil (list 5) 6)
An atom: NIL
and a list: (5)
and an integer: 6
The first argument to format is either t, nil, or a stream. T specifies
output to the terminal. Nil means not to print anything but to return a
string containing the output instead. Streams are general places for
output to go: they can specify a file, or the terminal, or another
program. This handout will not describe streams in any further detail.
第一個(gè)參數(shù)可以是 t,nil
或者一個(gè)流。t意味著輸出到終端;nil意味著不打印
任何東西,而是把它返回。流是用于輸出的通用方式:它可以是一個(gè)指定的文件,
或者一個(gè)終端,或者另一個(gè)程序。這里不再詳細(xì)描述流的更多細(xì)節(jié)。
The second argument is a formatting template, which is a string
optionally containing formatting directives.
第二個(gè)參數(shù)是個(gè)格式化模版,即一個(gè)包含格式化設(shè)定的字符串。
All remaining arguments may be referred to by the formatting
directives. LISP will replace the directives with some appropriate
characters based on the arguments to which they refer and then print
the resulting string.
所有其它的參數(shù)由格式化設(shè)定引用。LISP會(huì)根據(jù)標(biāo)示所引用的參數(shù),將其替換
為合適的字符,并返回結(jié)果字符串。
Format always returns nil unless its first argument is nil, in which
case it prints nothing and returns a string.
如果format的第一個(gè)參數(shù)是 nil
,它返回一個(gè)字符串,什么也不打印,否則
它總是返回 nil 。
There are three different directives in the above example: ~S, ~D, and
~%. The first one accepts any LISP object and is replaced by a printed
representation of that object (the same representation which is
produced by print). The second one accepts only integers. The third one
doesn't refer to an argument; it is always replaced by a carriage
return.
前面的例子中有三種不同的標(biāo)示:~S,~D和~%。第一個(gè)接受任意LISP對(duì)象并且將
其替換為這個(gè)對(duì)象的打印描述(與使用print打印出的描述信息相同)。第二個(gè)
Another useful directive is ~~, which is replaced by a single ~.
另一個(gè)常用的標(biāo)示是~~,它替換為單個(gè)~。
Refer to a LISP manual for (many, many) additional formatting
directives.
LISP手冊(cè)中介紹了其它(很多,很多)的格式化標(biāo)示。
Forms and the Top-Level Loop
The things which you type to the LISP interpreter are called forms; the
LISP interpreter repeatedly reads a form, evaluates it, and prints the
result. This procedure is called the read-eval-print loop.
我們輸入到LISP解釋器的東西被稱為語句;LISP解釋器逐條循環(huán)讀取每條語句,
進(jìn)行解析,將結(jié)果打印出來。這個(gè)過程被稱為讀取-解析-打印循環(huán)。
Some forms will cause errors. After an error, LISP will put you into
the debugger so you can try to figure out what caused the error. LISP
debuggers are all different; but most will respond to the command
"help" or ":help" by giving some form of help.
某些語句會(huì)發(fā)生錯(cuò)誤,LISP會(huì)引領(lǐng)我們進(jìn)入調(diào)試器,以便我們找出錯(cuò)誤原因。
LISP的各種調(diào)試器有很多差異,不過使用"help"或":help"命令就會(huì)給出一
些語句幫助。
In general, a form is either an atom (for example, a symbol, an
integer, or a string) or a list. If the form is an atom, LISP evaluates
it immediately. Symbols evaluate to their value; integers and strings
evaluate to themselves. If the form is a list, LISP treats its first
element as the name of a function; it evaluates the remaining elements
recursively, and then calls the function with the values of the
remaining elements as arguments.
通常,一個(gè)語句是一個(gè)原子(例如,一個(gè)符號(hào)或者整數(shù),或者字符串)或者一個(gè)列表,
如果換某個(gè)語句是原子,LISP立即解析它。符號(hào)解析為它們的值;整數(shù)和字符串解析
為它們自身。如果語句是一個(gè)列表,LISP視它的第一個(gè)元素為函數(shù)名;它遞歸的解析
其余的元素,然后將它們的值作為參數(shù)來調(diào)用這個(gè)函數(shù)。
For example, if LISP sees the form (+ 3 4), it treats + as the name of
a function. It then evaluates 3 to get 3 and 4 to get 4; finally it
calls + with 3 and 4 as the arguments. The + function returns 7, which
LISP prints.
例如,如果LISP遇到語句 (+ 3 4),它嘗試將 +
作為函數(shù)名。然后將3解析為3,4解
析為4;最后用3和4作為參數(shù)調(diào)用+。LISP打印出 +
函數(shù)的返回值7。
The top-level loop provides some other conveniences; one particularly
convenient convenience is the ability to talk about the results of
previously typed forms. LISP always saves its most recent three
results; it stores them as the values of the symbols *, **, and ***.
For example:
頂級(jí)循環(huán)還提供了一些其它的便利;一個(gè)特別方便的地方就是獲取以前輸入的
語句的結(jié)果。LISP總會(huì)保存最近三個(gè)結(jié)果;它將它們保存在*,**和***三個(gè)符
號(hào)的值中,例如:
> 3
3
> 4
4
> 5
5
> ***
3
> ***
4
> ***
5
> **
4
> *
4
Special forms
There are a number of special forms which look like function calls but
aren't. These include control constructs such as if statements and do
loops; assignments like setq, setf, push, and pop; definitions such as
defun and defstruct; and binding constructs such as let. (Not all of
these special forms have been mentioned yet. See below.)
有幾個(gè)特殊語句看起來像函數(shù)調(diào)用,但其實(shí)不是。這里面包括流程控制語句,例
如 if 語句和 do loops;賦值語句,例如 setq,
setf,push和pop;定義語句
例如 defun 和 defstruct;以及綁定構(gòu)造,如
let。(這里沒有提及所有的特殊
語句。我們繼續(xù)。)
One useful special form is the quote form: quote prevents its argument
from being evaluated. For example:
一個(gè)很有用的特殊語句是 quote
:quote取消其參數(shù)的綁定狀態(tài)。例如:
> (setq a 3)
3
> a
3
> (quote a)
A
> 'a ? ? ? ? ? ? ? ? ? ?;'a is an abbreviation for (quote a)
A
Another similar special form is the function form: function causes its
argument to be interpreted as a function rather than being evaluated.
For example:
另一個(gè)類似的語句是
fuction:function使得解釋器將其參數(shù)視為一個(gè)函數(shù)而不是
解析值,例如:
> (setq + 3)
3
> +
3
> '+
+
> (function +)
#<Function + @ #x-fbef9de>
> #'+ ? ? ? ? ? ? ? ? ? ;#'+ is an abbreviation for (function +)
#<Function + @ #x-fbef9de>
The function special form is useful when you want to pass a function as
an argument to another function. See below for some examples of
functions which take functions as arguments.
當(dāng)我們需要將一個(gè)函數(shù)作為參數(shù)傳遞給另一個(gè)函數(shù)時(shí)會(huì)用到
function 語句。后面
有些示例函數(shù)將函數(shù)作為參數(shù)。
Binding
Binding is lexically scoped assignment. It happens to the variables in
a function's parameter list whenever the function is called: the formal
parameters are bound to the actual parameters for the duration of the
function call. You can bind variables anywhere in a program with the
let special form, which looks like this:
綁定是詞匯作用域賦值(汗,怎么讀怎么別扭--譯者)。每當(dāng)函數(shù)調(diào)用時(shí),它就
發(fā)生于函數(shù)的參數(shù)列變量中:形式參數(shù)被取代為調(diào)用函數(shù)時(shí)的實(shí)際參數(shù)。你可以在
程序中隨處綁定變量,就像下面這樣:
? ? ? ?(let ((var1 val1)
? ? ? ? ? ? ?(var2 val2)
? ? ? ? ? ? ?...)
? ? ? ? ?body)
Let binds var1 to val1, var2 to val2, and so forth; then it executes
the statements in its body. The body of a let follows exactly the same
rules that a function body does. Some examples:
let把val1綁定到var1,把val2綁定到var2,依次類推;然后在它的程序體中執(zhí)
行語句。let的程序體與函數(shù)體的執(zhí)行規(guī)則完全相同。例如:
> (let ((a 3)) (+ a 1))
4
> (let ((a 2)
? ? ? ?(b 3)
? ? ? ?(c 0))
? ?(setq c (+ a b))
? ?c)
5
> (setq c 4)
4
> (let ((c 5)) c)
5
> c
4
Instead of (let ((a nil) (b nil)) ...), you can write (let (a b) ...).
你可以用 (let (a b) ...) 代替 (let ((a nil) (b nil)) ...) 。
The val1, val2, etc. inside a let cannot reference the variables var1,
var2, etc. that the let is binding. For example,
val1,val2等等。在 let 內(nèi)部不能引用
var1,var2等等let正在綁定的成員。
例如(簡(jiǎn)而言之,在參數(shù)表中,形式參數(shù)之間不能互相引用--譯者):
> (let ((x 1)
? ? ? ?(y (+ x 1)))
? ?y)
Error: Attempt to take the value of the unbound symbol X
If the symbol x already has a global value, stranger happenings will
result:
如果符號(hào)x已經(jīng)有了一個(gè)全局值,會(huì)產(chǎn)生一些奇怪的結(jié)果:
> (setq x 7)
7
> (let ((x 1)
? ? ? ?(y (+ x 1)))
? ?y)
8
The let* special form is just like let except that it allows values to
reference variables defined earlier in the let*. For example,
let* 語句類似于 let,但它允許引用之前在 let*
中定義的變量的值。例如:
> (setq x 7)
7
> (let* ((x 1)
? ? ? ? (y (+ x 1)))
? ?y)
2
The form
語句
? ? ? ?(let* ((x a)
? ? ? ? ? ? ? (y b))
? ? ? ? ?...)
is equivalent to
等價(jià)于
? ? ? ?(let ((x a))
? ? ? ? ?(let ((y b))
? ? ? ? ? ?...))
Dynamic Scoping
The let and let* forms provide lexical scoping, which is what you
expect if you're used to programming in C or Pascal. Dynamic scoping is
what you get in BASIC: if you assign a value to a dynamically scoped
variable, every mention of that variable returns that value until you
assign another value to the same variable.
與我們?cè)贑或Pascal中編寫程序不同,let 和 let*
語句提供了詞匯作用域。動(dòng)態(tài)
作用域是我們?cè)贐ASIC里用的那種:如果我們給一個(gè)動(dòng)態(tài)作用域變量賦了值,那么
所有對(duì)這個(gè)變量的訪問都會(huì)取得這個(gè)值,直到給同一個(gè)變量賦了另一個(gè)值為止。
In LISP, dynamically scoped variables are called special variables. You
can declare a special variable with the defvar special form. Here are
some examples of lexically and dynamically scoped variables.
在LISP中,動(dòng)態(tài)作用域變量被稱為特化變量 。你可以用
special 語句 defvar
定義一個(gè)特化變量。這里有一些詞匯化和動(dòng)態(tài)作用域變量的示例。
In this example, the function check-regular references a regular (ie,
lexically scoped) variable. Since check-regular is lexically outside of
the let which binds regular, check-regular returns the variable's
global value.
在以下示例中,check-regular 函數(shù)引用一個(gè) regular
(也就是一個(gè)詞匯作用域)
變量。因?yàn)?check-regular 在綁定 regular 的 let
外部詞匯化,check-regular
返回變量的全局值。
> (setq regular 5)
5
> (defun check-regular () regular)
CHECK-REGULAR
> (check-regular)
5
> (let ((regular 6)) (check-regular))
5
In this example, the function check-special references a special (ie,
dynamically scoped) variable. Since the call to check-special is
temporally inside of the let which binds special, check-special returns
the variable's local value.
在這個(gè)例子中,函數(shù) check-special 引用了一個(gè)
特化(動(dòng)態(tài)作用域)變量。
因此 check-special 調(diào)用臨時(shí)發(fā)生于特化綁定的 let
內(nèi)部,check-special
返回變量的局部值。
> (defvar *special* 5)
*SPECIAL*
> (defun check-special () *special*)
CHECK-SPECIAL
> (check-special)
5
> (let ((*special* 6)) (check-special))
6
By convention, the name of a special variable begins and ends with a *.
Special variables are chiefly used as global variables, since
programmers usually expect lexical scoping for local variables and
dynamic scoping for global variables.
方便起見,特化變量以一個(gè) *
開始和結(jié)束。特化變量主要用于全局變量,因?yàn)?br style="word-wrap:break-word" /> 程序員通常期望局部變量使用詞匯作用域,全局變量使用動(dòng)態(tài)作用域。
For more information on the difference between lexical and dynamic
scoping, see _Common LISP: the Language_.
詞匯和動(dòng)態(tài)作用域的更多差異參見《Common LISP: the
Language》。
Arrays
The function make-array makes an array. The aref function accesses its
elements. All elements of an array are initially set to nil. For
example:
make-array 函數(shù)定義一個(gè)數(shù)組。aref
函數(shù)訪問它的元素。所有元素初始化為nil。
例如:
> (make-array '(3 3))
#2a((NIL NIL NIL) (NIL NIL NIL) (NIL NIL NIL))
> (aref * 1 1)
NIL
> (make-array 4) ? ? ? ?;1D arrays don't need the extra parens
#(NIL NIL NIL NIL)
Array indices always start at 0.
數(shù)組索引從0開始。
See below for how to set the elements of an array.
以后討論如何設(shè)置一個(gè)數(shù)組的元素。
Strings
A string is a sequence of characters between double quotes. LISP
represents a string as a variable-length array of characters. You can
write a string which contains a double quote by preceding the quote
with a backslash; a double backslash stands for a single backslash. For
example:
字符串是包含在雙引號(hào)之間的字符串。LISP
用字符串代表一個(gè)變長(zhǎng)字符數(shù)組。
我們可以用一個(gè)反斜杠加一個(gè)雙引號(hào)來表示字符串中的雙引號(hào),兩個(gè)反斜杠表示
一個(gè)單獨(dú)的反斜杠。例如:
? ? ? ?"abcd" has 4 characters
? ? ? ?"\"" has 1 character
? ? ? ?"\\" has 1 character
Here are some functions for dealing with strings:
有一些函數(shù)可以用于操作字符串:
> (concatenate 'string "abcd" "efg")
"abcdefg"
> (char "abc" 1)
#\b ? ? ? ? ? ? ? ? ? ? ;LISP writes characters preceded by #\
> (aref "abc" 1)
#\b ? ? ? ? ? ? ? ? ? ? ;remember, strings are really arrays
The concatenate function can actually work with any type of sequence:
concatenate 函數(shù)可以用于連接任何類型的序列:
> (concatenate 'string '(#\a #\b) '(#\c))
"abc"
> (concatenate 'list "abc" "de")
(#\a #\b #\c #\d #\e)
> (concatenate 'vector '#(3 3 3) '#(3 3 3))
#(3 3 3 3 3 3)
Structures
LISP structures are analogous to C structs or Pascal records. Here is
an example:
LISP 結(jié)構(gòu)類似于C結(jié)構(gòu)或Pasacal記錄。如下所示:
> (defstruct foo
? ?bar
? ?baaz
? ?quux)
FOO
This example defines a data type called foo which is a structure
containing 3 fields. It also defines 4 functions which operate on this
data type: make-foo, foo-bar, foo-baaz, and foo-quux. The first one
makes a new object of type foo; the others access the fields of an
object of type foo. Here is how to use these functions:
這個(gè)示例定義了一個(gè)名為 foo
的數(shù)據(jù)類型,它是一個(gè)帶有三個(gè)字段的結(jié)構(gòu)。
它同時(shí)定義了4個(gè)函數(shù)用于操作這個(gè)數(shù)據(jù)類型:make-foo,foo-ba,foo-baaz和
foo-quux。第一個(gè)函數(shù)構(gòu)造了一個(gè)foo類型的新對(duì)象,另外三個(gè)用于訪問一個(gè)
foo類型的對(duì)象。以下是這些函數(shù)的用法:
> (make-foo)
#s(FOO :BAR NIL :BAAZ NIL :QUUX NIL)
> (make-foo :baaz 3)
#s(FOO :BAR NIL :BAAZ 3 :QUUX NIL)
> (foo-bar *)
NIL
> (foo-baaz **)
3
The make-foo function can take a keyword argument for each of the
fields a structure of type foo can have. The field access functions
each take one argument, a structure of type foo, and return the
appropriate field.
meke-foo
函數(shù)可以使用foo結(jié)構(gòu)類型的字段作為關(guān)鍵字參數(shù)。字段訪問函數(shù)以
foo類型的結(jié)構(gòu)為參數(shù),返回對(duì)應(yīng)的字段。
See below for how to set the fields of a structure.
以后討論如何設(shè)置一個(gè)結(jié)構(gòu)的字段。
Setf
Certain forms in LISP naturally define a memory location. For example,
if the value of x is a structure of type foo, then (foo-bar x) defines
the bar field of the value of x. Or, if the value of y is a one-
dimensional array, (aref y 2) defines the third element of y.
LISP確認(rèn)語句的時(shí)間,自然就會(huì)定義一個(gè)內(nèi)存區(qū)域。例如,如果x的值是foo類型
的一個(gè)結(jié)構(gòu),(foo-bar
x)定義x中bar字段的值。或者,如果y是一個(gè)一維數(shù)組,
(aref y 2)定義y的第三個(gè)元素。
The setf special form uses its first argument to define a place in
memory, evaluates its second argument, and stores the resulting value
in the resulting memory location. For example,
setf
語句用于在內(nèi)存中將它的第一個(gè)參數(shù)定位到第二個(gè)參數(shù)上,并且返回內(nèi)存
區(qū)域的結(jié)果值。例如:
> (setq a (make-array 3))
#(NIL NIL NIL)
> (aref a 1)
NIL
> (setf (aref a 1) 3)
3
> a
#(NIL 3 NIL)
> (aref a 1)
3
> (defstruct foo bar)
FOO
> (setq a (make-foo))
#s(FOO :BAR NIL)
> (foo-bar a)
NIL
> (setf (foo-bar a) 3)
3
> a
#s(FOO :BAR 3)
> (foo-bar a)
3
Setf is the only way to set the fields of a structure or the elements
of an array.
setf是給結(jié)構(gòu)的字段或者數(shù)組的元素賦值的唯一方法。
Here are some more examples of setf and related functions.
這里還有一些關(guān)于setf和相關(guān)函數(shù)的示例。
> (setf a (make-array 1)) ? ? ? ;setf on a variable is equivalent to setq
#(NIL)
> (push 5 (aref a 1)) ? ? ? ? ? ;push can act like setf
(5)
> (pop (aref a 1)) ? ? ? ? ? ? ?;so can pop
5
> (setf (aref a 1) 5)
5
> (incf (aref a 1)) ? ? ? ? ? ? ;incf reads from a place, increments,
6 ? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ;and writes back
> (aref a 1)
6
Booleans and Conditionals
LISP uses the self-evaluating symbol nil to mean false. Anything other
than nil means true. Unless we have a reason not to, we usually use the
self-evaluating symbol t to stand for true.
LISP 用自解析符號(hào) nil 來代表 false。任何 nil
之外的其它東西都代表 true。
除非有什么特別的原因,我們總是使用 true
的標(biāo)準(zhǔn)自解析符號(hào) t。
LISP provides a standard set of logical functions, for example and, or,
and not. The and and or connectives are short-circuiting: and will not
evaluate any arguments to the right of the first one which evaluates to
nil, while or will not evaluate any arguments to the right of the first
one which evaluates to t.
LISP提供了一個(gè)邏輯運(yùn)算的標(biāo)準(zhǔn)函數(shù)集,例如,與、或、非。與和或支持短路算法:
在遇到第一個(gè)nil后不再解析右面的參數(shù),而與在遇到第一個(gè)t后也不再解析右面的
參數(shù)。
LISP also provides several special forms for conditional execution. The
simplest of these is if. The first argument of if determines whether
the second or third argument will be executed:
LISP還為條件控制提供了幾個(gè)特殊語句。最簡(jiǎn)單的是if。if語句的第一個(gè)參數(shù)決定了
執(zhí)行第二或第三個(gè)參數(shù)中的哪一個(gè):
> (if t 5 6)
5
> (if nil 5 6)
6
> (if 4 5 6)
5
If you need to put more than one statement in the then or else clause
of an if statement, you can use the progn special form. Progn executes
each statement in its body, then returns the value of the final one.
如果你需要在then或else塊中放置超過一行的語句,可以使用特殊語句
progn。
Progn
在它的程序體內(nèi)依次執(zhí)行每一條語句,返回最后一個(gè)結(jié)果。
> (setq a 7)
7
> (setq b 0)
0
> (setq c 5)
5
> (if (> a 5)
? ?(progn
? ? ?(setq a (+ b 7))
? ? ?(setq b (+ c 8)))
? ?(setq b 4))
13
An if statement which lacks either a then or an else clause can be
written using the when or unless special form:
一個(gè)沒有 else 或 when 的語句可以寫為 when 或 unless
語句。
> (when t 3)
3
> (when nil 3)
NIL
> (unless t 3)
NIL
> (unless nil 3)
3
When and unless, unlike if, allow any number of statements in their
bodies. (Eg, (when x a b c) is equivalent to (if x (progn a b c)).)
與 if 不同,when 和 unless
允許在程序體內(nèi)放置任意多的語句。(例如,
(when x a b c) 等價(jià)于 (if x (progn a b c)))
> (when t
? ?(setq a 5)
? ?(+ a 6))
11
More complicated conditionals can be defined using the cond special
form, which is equivalent to an if ... else if ... fi construction.
更復(fù)雜的條件控制可以用 cond
語句定義實(shí)現(xiàn),它定價(jià)于一個(gè) if ... else
if ... fi 條件。
A cond consists of the symbol cond followed by a number of cond
clauses, each of which is a list. The first element of a cond clause is
the condition; the remaining elements (if any) are the action. The cond
form finds the first clause whose condition evaluates to true (ie,
doesn't evaluate to nil); it then executes the corresponding action and
returns the resulting value. None of the remaining conditions are
evaluated; nor are any actions except the one corresponding to the
selected condition. For example:
一個(gè) cond 由 symbol
符號(hào)和其后的若干條件分支組成,每一個(gè)分支是一個(gè)
list。
cond
分支的第一個(gè)元素是條件;其它的元素(如果有的話)是動(dòng)作。cond語句查
找第一個(gè)條件解析為 true
的分支,執(zhí)行其響應(yīng)動(dòng)作并返回結(jié)果值。其它條件不會(huì)
被解析,除了這個(gè)響應(yīng)之外的分支也不會(huì)執(zhí)行。例如:
> (setq a 3)
3
> (cond
? ((evenp a) a) ? ? ? ?;if a is even return a
? ((> a 7) (/ a 2)) ? ?;else if a is bigger than 7 return a/2
? ((< a 5) (- a 1)) ? ?;else if a is smaller than 5 return a-1
? (t 17)) ? ? ? ? ? ? ?;else return 17
2
If the action in the selected cond clause is missing, cond returns what
the condition evaluated to:
如果選定的分支沒有響應(yīng)動(dòng)作,cond
返回條件的解析結(jié)果。
> (cond ((+ 3 4)))
7
Here's a clever little recursive function which uses cond. You might be
interested in trying to prove that it terminates for all integers x at
least 1. (If you succeed, please publish the result.)
這里用 cond
巧妙的實(shí)現(xiàn)了一個(gè)遞歸函數(shù)。你可能會(huì)有興趣證明它對(duì)于所有的整數(shù)
x 都少有個(gè)終結(jié)。(如果你成功了,請(qǐng)發(fā)表出來。)
> (defun hotpo (x steps) ? ? ? ?;hotpo stands for Half Or Triple Plus One
? ?(cond
? ? ((= x 1) steps)
? ? ((oddp x) (hotpo (+ 1 (* x 3)) (+ 1 steps)))
? ? (t (hotpo (/ x 2) (+ 1 steps)))))
A
> (hotpo 7 0)
16
The LISP case statement is like a C switch statement:
LISP 的 case 語句類似于 C 的 switch 語句:
> (setq x 'b)
B
> (case x
? (a 5)
? ((d e) 7)
? ((b f) 3)
? (otherwise 9))
3
The otherwise clause at the end means that if x is not a, b, d, e, or
f, the case statement will return 9.
末尾的 otherwise 語句意味著 x
不是a、b、c、d、e、f,case語句將會(huì)返回9。
Iteration
The simplest iteration construct in LISP is loop: a loop construct
repeatedly executes its body until it hits a return special form. For
example,
LISP 中最簡(jiǎn)單的迭代結(jié)構(gòu)是 loop:loop
結(jié)構(gòu)反復(fù)執(zhí)行它的程序體直到到達(dá)
一個(gè)返回語句,例如:
> (setq a 4)
4
> (loop
? (setq a (+ a 1))
? (when (> a 7) (return a)))
8
> (loop
? (setq a (- a 1))
? (when (< a 3) (return)))
NIL
The next simplest is dolist: dolist binds a variable to the elements of
a list in order and stops when it hits the end of the list.
dolist是下一個(gè)最簡(jiǎn)單的:dolist把一個(gè)變量依次綁定到一個(gè)列表的各個(gè)元素上,
在到達(dá)列表結(jié)尾時(shí)結(jié)束。
> (dolist (x '(a b c)) (print x))
A
B
C
NIL
Dolist always returns nil. Note that the value of x in the above
example was never nil: the NIL below the C was the value that dolist
returned, printed by the read-eval-print loop.
Dolist 總是返回nil。注意上例中的 x
永遠(yuǎn)不會(huì)為nil:C后面的NIL是dolist
返回的,它被讀取-解析-打印循環(huán)所打印。
The most complicated iteration primitive is called do. A do statement
looks like this:
更復(fù)雜的迭代稱為 do。do語句的示例如下:
> (do ((x 1 (+ x 1))
? ? ? (y 1 (* y 2)))
? ? ?((> x 5) y)
? ?(print y)
? ?(print 'working))
1
WORKING
2
WORKING
4
WORKING
8
WORKING
16
WORKING
32
The first part of a do specifies what variables to bind, what their
initial values are, and how to update them. The second part specifies a
termination condition and a return value. The last part is the body. A
do form binds its variables to their initial values like a let, then
checks the termination condition. As long as the condition is false, it
executes the body repeatedly; when the condition becomes true, it
returns the value of the return-value form.
do的第一步是指定綁定的變量,它們的初始值,以及如何更新。第二步是指定一
個(gè)終止條件和返回值。最后是程序體。do語句像let一樣把它的變量綁定到初始值,
然后校驗(yàn)終止條件。條件為false時(shí),它重復(fù)執(zhí)行程序體;當(dāng)條件為true,它返回
return-value 語句的值。
The do* form is to do as let* is to let.
do* 語句之于 do 如同 let* 之于 let。
Non-local Exits
The return special form mentioned in the section on iteration is an
example of a nonlocal return. Another example is the return-from form,
which returns a value from the surrounding function:
前一節(jié)中迭代示例里的renturn語句是一個(gè)無定位返回的示例,另一個(gè)是
return-from,它從包圍它的函數(shù)中返回指定值。
> (defun foo (x)
? ?(return-from foo 3)
? ?x)
FOO
> (foo 17)
3
Actually, the return-from form can return from any named block -- it's
just that functions are the only blocks which are named by default. You
can create a named block with the block special form:
實(shí)際上,return-from
語句可以從任何已命名的語句塊中退出--只是默認(rèn)情況下
函數(shù)是唯一的命名語句塊而已。我們可以用 block
語句自己定義一個(gè)命名語句塊。
> (block foo
? ?(return-from foo 7)
? ?3)
7
The return special form can return from any block named nil. Loops are
by default labelled nil, but you can make your own nil-labelled blocks:
return
語句可以從任何nil命名的語句塊中返回。默認(rèn)情況下循環(huán)是nil命名,而
我們可以創(chuàng)建自己的nil標(biāo)記語句塊。
> (block nil
? ?(return 7)
? ?3)
7
Another form which causes a nonlocal exit is the error form:
另外一個(gè)無定位退出語句是 error 語句:
> (error "This is an error")
Error: This is an error
The error form applies format to its arguments, then places you in the
debugger.
error語句格式化它的參數(shù),然后進(jìn)入調(diào)試器。
Funcall, Apply, and Mapcar
Earlier I promised to give some functions which take functions as
arguments. Here they are:
早先我承諾介紹一些可以將函數(shù)作為參數(shù)調(diào)用函數(shù),它們?cè)谶@里:
> (funcall #'+ 3 4)
7
> (apply #'+ 3 4 '(3 4))
14
> (mapcar #'not '(t nil t nil t nil))
(NIL T NIL T NIL T)
Funcall calls its first argument on its remaining arguments.
funcall 用它的其它參數(shù)調(diào)用它的第一個(gè)參數(shù)。
Apply is just like funcall, except that its final argument should be a
list; the elements of that list are treated as if they were additional
arguments to a funcall.
Apply和funcall很相像,不過它的最后一個(gè)參數(shù)可以是一個(gè)列表;這個(gè)列表被看
作是funcall的附加參數(shù)。
The first argument to mapcar must be a function of one argument; mapcar
applies this function to each element of a list and collects the
results in another list.
mapcar的第一個(gè)參數(shù)必須是一個(gè)單參數(shù)的函數(shù);mapcar在列表上逐個(gè)元素應(yīng)用該
函數(shù),并將返回值包含如另一個(gè)鏈表。
Funcall and apply are chiefly useful when their first argument is a
variable. For instance, a search engine could take a heuristic function
as a parameter and use funcall or apply to call that function on a
state description. The sorting functions described later use funcall
to call their comparison functions.
Funcall和apply主要用于第一個(gè)參數(shù)是變量的場(chǎng)合。例如,搜索引擎把一個(gè)啟發(fā)式
函數(shù)作為參數(shù),在一個(gè)狀態(tài)描述上應(yīng)用funcall或者apply。
Mapcar, along with nameless functions (see below), can replace many
loops.
Mapcar配合匿名函數(shù)(后面介紹),可以取代很多循環(huán)。
Lambda
If you just want to create a temporary function and don't want to
bother giving it a name, lambda is what you need.
如果你只是想創(chuàng)建一個(gè)臨時(shí)函數(shù),并不想給它一個(gè)命名,lambda如你所愿。
> #'(lambda (x) (+ x 3))
(LAMBDA (X) (+ X 3))
> (funcall * 5)
8
The combination of lambda and mapcar can replace many loops. For
example, the following two forms are equivalent:
lambda和mapcar的組合可以取代很多循環(huán),例如,如下的兩個(gè)語句是等價(jià)的:
> (do ((x '(1 2 3 4 5) (cdr x))
? ? ? (y nil))
? ? ?((null x) (reverse y))
? ?(push (+ (car x) 2) y))
(3 4 5 6 7)
> (mapcar #'(lambda (x) (+ x 2)) '(1 2 3 4 5))
(3 4 5 6 7)
Sorting
LISP provides two primitives for sorting: sort and stable-sort.
LISP提供兩種主要的排序:排序和穩(wěn)定排序。
> (sort '(2 1 5 4 6) #'<)
(1 2 4 5 6)
> (sort '(2 1 5 4 6) #'>)
(6 5 4 2 1)
The first argument to sort is a list; the second is a comparison
function. The sort function does not guarantee stability: if there are
two elements a and b such that (and (not (< a b)) (not (< b a))), sort
may arrange them in either order. The stable-sort function is exactly
like sort, except that it guarantees that two equivalent elements
appear in the sorted list in the same order that they appeared in the
original list.
sort的第一個(gè)參數(shù)是一個(gè)列表,第二個(gè)是一個(gè)比較函數(shù)。sort函數(shù)不保證穩(wěn)定性:
如果這里有a和b兩個(gè)元素,(and (not (< a b)) (not (< b
a))),sort可能會(huì)改
變它們的位置。stable-sort(穩(wěn)定排序)與sort非常像,不過它確保兩個(gè)相等
的元素在排序后的列表中的順序與排序前列表中的順序相同。
Be careful: sort is allowed to destroy its argument, so if the original
sequence is important to you, make a copy with the copy-list or
copy-seq
function.
注意:sort可能會(huì)破壞它的參數(shù),如果原始序列對(duì)我們很重要,最好使用copy-list
或copy-seq函數(shù)創(chuàng)建一個(gè)副本。
Equality
LISP has many different ideas of equality. Numerical equality is
denoted by =. Two symbols are eq if and only if they are identical. Two
copies of the same list are not eq, but they are equal.
關(guān)于相等,LISP有很多不同的觀點(diǎn)。數(shù)值相等意味著=。兩個(gè)符號(hào)當(dāng)且僅當(dāng)他們完全
一樣時(shí)相同。同一個(gè)列表的兩個(gè)副本不相同,但是它們相等。
> (eq 'a 'a)
T
> (eq 'a 'b)
NIL
> (= 3 4)
NIL
> (eq '(a b c) '(a b c))
NIL
> (equal '(a b c) '(a b c))
T
> (eql 'a 'a)
T
> (eql 3 3)
T
The eql predicate is equivalent to eq for symbols and to = for numbers
or the same type:
謂詞eql代表相等,它對(duì)于符號(hào)表示相同,對(duì)于數(shù)值表示=。
> (eql 2.0 2)
NIL
> (= 2.0 2)
T
> (eq 12345678901234567890 12345678901234567890)
NIL
> (= 12345678901234567890 12345678901234567890)
T
> (eql 12345678901234567890 12345678901234567890)
T
The equal predicate is equivalent to eql for symbols and numbers. It is
true for two conses if and only if their cars are equal and their cdrs
are equal. It is true for two structures if and only if the structures
are the same type and their corresponding fields are equal.
equal謂詞對(duì)于符號(hào)和數(shù)值是相等。當(dāng)且僅當(dāng)兩個(gè) conse
的car和cdr都相等時(shí)它們
才是相等的。當(dāng)且僅當(dāng)兩個(gè)結(jié)構(gòu)是同類型而且各字段都相等時(shí)它們相等。
Some Useful List Functions
These functions all manipulate lists.
這些函數(shù)都用來操作列表。
> (append '(1 2 3) '(4 5 6)) ? ?;concatenate lists
(1 2 3 4 5 6)
> (reverse '(1 2 3)) ? ? ? ? ? ?;reverse the elements of a list
(3 2 1)
> (member 'a '(b d a c)) ? ? ? ?;set membership -- returns the first tail
(A C) ? ? ? ? ? ? ? ? ? ? ? ? ? ;whose car is the desired element
> (find 'a '(b d a c)) ? ? ? ? ?;another way to do set membership
A
> (find '(a b) '((a d) (a d e) (a b d e) ()) :test #'subsetp)
(A B D E) ? ? ? ? ? ? ? ? ? ? ? ;find is more flexible though
> (subsetp '(a b) '(a d e)) ? ? ;set containment
NIL
> (intersection '(a b c) '(b)) ?;set intersection
(B)
> (union '(a) '(b)) ? ? ? ? ? ? ;set union
(A B)
> (set-difference '(a b) '(a)) ?;set difference
(B)
Subsetp, intersection, union, and set-difference all assume that each
argument contains no duplicate elements -- (subsetp '(a a) '(a b b)) is
allowed to fail, for example.
Subsetp,intersection,union和set-difference都允許各個(gè)參數(shù)包含不匹配的元素
--例如,(subsetp '(a a) '(a b b))可以為fail。
Find, subsetp, intersection, union, and set-difference can all take a
:test keyword argument; by default, they all use eql.
Find,subsetp,intersection,union和set-difference都可以接受一個(gè):test關(guān)鍵
字參數(shù);默認(rèn)情況下,它們是等價(jià)的。
Getting Started with Emacs
You can use Emacs to edit LISP code: most Emacses are set up to enter
LISP mode automatically when they find a file which ends in .lisp, but
if yours isn't, you can type M-x lisp-mode.
你可以使用Emacs編輯LISP代碼:Emaces在打開.lisp文件時(shí)總會(huì)自動(dòng)進(jìn)入LISP模式,
不過如果我們的Emacs沒有成功進(jìn)入這個(gè)狀態(tài),可以通過輸入M-x
lisp-mode做到。
You can run LISP under Emacs, too: make sure that there is a command in
your path called "lisp" which runs your favorite LISP. For example, you
could type
我們也可以在Emacs下運(yùn)行LISP:先確保在我們的私人路徑下可以運(yùn)行一個(gè)叫
"LISP"的命令。例如,我們可以輸入:
? ? ? ?ln -s /usr/local/bin/clisp ~/bin/lisp
Then in Emacs type M-x run-lisp. You can send LISP code to the LISP you
just started, and do all sorts of other cool things; for more
information, type C-h m from any buffer which is in LISP mode.
然后在Emacs中輸入 M-x
run-lip。我們可以向LISP發(fā)送先前的LISP代碼,做其它
很酷的事情;在LISP模式下的任何緩沖輸入 C-h
m可以得到進(jìn)一步的信息。
Actually, you don't even need to make a link. Emacs has a variable
called inferior-lisp-program; so if you add the line
實(shí)際上,我們甚至不需要建立鏈接。Emacs有一個(gè)變量叫
inferior-lisp-program;
所以我們可以把下面這行
? ? ? ?(setq inferior-lisp-program "/usr/local/bin/clisp")
to your .emacs file, Emacs will know where to find CLISP when
you type M-x run-lisp.
輸入到自己的 .emacs 文件中,Emacs就會(huì)知道在你輸入 M-x
run-lisp時(shí)去哪里尋找
CLISP。
總結(jié)
- 上一篇: Android中用GridView实现九
- 下一篇: 用Hadoop进行分布式并行编程