日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 >

Lisp入门教程

發布時間:2025/6/15 12 豆豆
生活随笔 收集整理的這篇文章主要介紹了 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 >

? ? ? ? ? ? ? ? ? ? ? ? ? 簡體中文版翻譯:
? ? ? ? ? ? ? ? ? ? ? ? ? ? ? ?劉鑫
? ? ? ? ? ? ? ? ? ? ? ?< 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 入門教程是針對 CMU
環境編寫,所以在其它環境運行
LISP時可能會有細節上的區別。

Further Information

附:

The best LISP textbook I know of is

?Guy L. Steele Jr. _Common LISP: the Language_. Digital Press. 1984.

據我所知最好的 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.)

第一版很容易閱讀,第二版介紹了更新的標準。(兩個標準的差異很 小,對于粗
心的程序員沒有什么區別。)

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
寫了一本,不過我從來沒讀過,所以不能對那本書
發表評論。

Symbols

符號

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:

符號僅僅是字符串。你可以在符號中包含字母、數字、連接符等等,唯一的限制就
是要以字母開頭。(如果你只輸入數字,最多再以一個連接符開頭的話,LISP會認
為你輸入了一個整數而不是符號。)例如:

? ? ? ?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.)

接下來我們可以做些事情。(">"標記表示你向LISP輸入的東西,其它的是LISP
打印返回給你的。";"是LISP的注釋符:";"后面的整行都會被忽略。)

> (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:

有兩個特殊的符號, t 和 nil 。 t 的值總是定義為 t
,nil 的值總是定義為
nil 。LISP用 t 和 nil 代表 true 和
false。以下是使用這個功能的 if 語句
,后面再做詳細說明:

> (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.)

最后一個例子看起來很怪,但是沒有錯: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
這樣的符號被稱為自解析符號,因為他們解析為自身。自解析符號稱為
關鍵字;任一以冒號開頭的符號都是關鍵字。(下面是一些關鍵字的應用)如下
所示:

> :this-is-a-keyword
:THIS-IS-A-KEYWORD
> :so-is-this
:SO-IS-THIS
> :me-too
:ME-TOO



Numbers

數值

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:

數值類型是數字文本,可能會以 + 或 -
開頭。實數和整數很相像,但是它帶有
小數點,還可能寫成科學計數法。有理數就像是兩個整數之間帶有一個/。LISP支
持復數,寫為#c(r
i)(r表示實部,i表示虛部)。以上統稱為數值。下面是一
些數值:

? ? ? ?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:

標準的計算函數包括: +, -, *, /, floor, ceiling, mod, sin,
cos, tan,
sqrt, exp, expt
等等。所有這些函數都可以接受任意數值類型參數。+、-、*

/返回盡可能大的類型:一個整數加一個有理數返回有理數,一個有理數加一個實數
是一個實數,一個實數加一個復數是一個復數。如下所示:

> (+ 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.)

對于整數來說,唯一的大小限制就是機器的內存。當然大數值運算(這
會調用大整數)可能會很慢。(因此我們可以計算有理數,尤其是小整數和浮點數
的比較運算)

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
就是一個包含兩個字段的記錄。出于歷史原因,兩個字段分別被稱為
"car"和"cdr"。(在第一臺實現LISP的機器上,用CAR和CDR代表"地址寄
存器的內容"和"指令寄存器的內容"。Conses的實現主要依靠這兩個寄存器。)

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:

你可以構造conses之外的結構。可能最簡單的是鏈表:每一個cons的car指向鏈表
的一個元素,cdr指向另一個cons或者nil。我們可以使用list函數構造鏈表。

> (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
用一種特殊的方式打印鏈表:它忽略掉某些分隔和括號。
規則如下:如果某個 cons 的 cdr 是 nil ,LISP 不打印 nil
和段標記,如果
cons A 的 cdr 是 cons B,LISP不打印 cons B 的括號和 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.

最后一個例子相當于調用(list 4 5 6)。要注意的是這里
nil 表示沒有元素的空
鏈表:包含兩個元素的鏈表(a
b)中,cdr是(b),一個含有單個元素的鏈表;包含
一個元素的鏈表(b),cdr是nil,故此這里必然是一個沒有元素的鏈表。

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:

如果你把鏈表存儲在變量中,可以將它當作堆棧來使用:

> (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:

前面我們討論過一些函數的例子,這里還有更多:

> (+ 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.

當我們定義函數的時候,設定了兩個參數,x 和
y。現在當我們調用 foo,需要
給出兩個參數:第一個在 foo 函數調用時成為 x
的值,第二個成為 y 的值。
在LISP中,大部分的變量都是局部的,如果 foo 調用了
bar ,bar中雖然使用了
名字為x的引用,但bar 得不到 foo 中的 x 。

The process of assigning a symbol a value for the duration of some
lexical scope is called binding.

在調用過程中給一個符號賦值的操作被稱為綁定。

You can specify optional arguments for your functions. Any argument
after the symbol &optional is optional:

我們可以給函數指定可選參數,在符號&optional
之后的參數是可選參數:

> (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函數的調用規則是要給出一個或兩個參數。如果它用一個參數調用,x
將會綁
定到這個參數值上,而 y 就是
nil;如果用兩個參數調用它,x和y會分別綁定
到第一和第二個值上。

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
函數有兩個可選參數。它為它們分別提供了默認值:如果調用者只給出了一
個參數,z會綁定為10而不是nil,如果調用者沒有給出參數,x會綁定為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:

在參數列表的最后設置一個 &rest
參數,可以使我們的函數接受任意數目的參數。
LISP把所有的附加參數都放進一個鏈表并綁定到 &rest
參數。如下:

> (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.

最后,我們可以為函數指定一種被稱為關鍵字參數的可選參數。調用者可以用
任意順序調用這些參數,因為他們已經通過關鍵字標示出來。

> (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:

關鍵字參數也可以有默認值:

> (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.

某些函數可以用來輸出。最簡單的一個是
print,它可以打印參數并且返回
它們。

> (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:

如果你需要更復雜的輸出,可能會用到
format,這里有個例子:

> (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.

第一個參數可以是 t,nil
或者一個流。t意味著輸出到終端;nil意味著不打印
任何東西,而是把它返回。流是用于輸出的通用方式:它可以是一個指定的文件,
或者一個終端,或者另一個程序。這里不再詳細描述流的更多細節。

The second argument is a formatting template, which is a string
optionally containing formatting directives.

第二個參數是個格式化模版,即一個包含格式化設定的字符串。

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.

所有其它的參數由格式化設定引用。LISP會根據標示所引用的參數,將其替換
為合適的字符,并返回結果字符串。

Format always returns nil unless its first argument is nil, in which
case it prints nothing and returns a string.

如果format的第一個參數是 nil
,它返回一個字符串,什么也不打印,否則
它總是返回 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.

前面的例子中有三種不同的標示:~S,~D和~%。第一個接受任意LISP對象并且將
其替換為這個對象的打印描述(與使用print打印出的描述信息相同)。第二個

Another useful directive is ~~, which is replaced by a single ~.

另一個常用的標示是~~,它替換為單個~。

Refer to a LISP manual for (many, many) additional formatting
directives.

LISP手冊中介紹了其它(很多,很多)的格式化標示。

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解釋器逐條循環讀取每條語句,
進行解析,將結果打印出來。這個過程被稱為讀取-解析-打印循環。

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.

某些語句會發生錯誤,LISP會引領我們進入調試器,以便我們找出錯誤原因。
LISP的各種調試器有很多差異,不過使用"help"或":help"命令就會給出一
些語句幫助。

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.

通常,一個語句是一個原子(例如,一個符號或者整數,或者字符串)或者一個列表,
如果換某個語句是原子,LISP立即解析它。符號解析為它們的值;整數和字符串解析
為它們自身。如果語句是一個列表,LISP視它的第一個元素為函數名;它遞歸的解析
其余的元素,然后將它們的值作為參數來調用這個函數。

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),它嘗試將 +
作為函數名。然后將3解析為3,4解
析為4;最后用3和4作為參數調用+。LISP打印出 +
函數的返回值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:

頂級循環還提供了一些其它的便利;一個特別方便的地方就是獲取以前輸入的
語句的結果。LISP總會保存最近三個結果;它將它們保存在*,**和***三個符
號的值中,例如:

> 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.)

有幾個特殊語句看起來像函數調用,但其實不是。這里面包括流程控制語句,例
如 if 語句和 do loops;賦值語句,例如 setq,
setf,push和pop;定義語句
例如 defun 和 defstruct;以及綁定構造,如
let。(這里沒有提及所有的特殊
語句。我們繼續。)

One useful special form is the quote form: quote prevents its argument
from being evaluated. For example:

一個很有用的特殊語句是 quote
:quote取消其參數的綁定狀態。例如:

> (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:

另一個類似的語句是
fuction:function使得解釋器將其參數視為一個函數而不是
解析值,例如:

> (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.

當我們需要將一個函數作為參數傳遞給另一個函數時會用到
function 語句。后面
有些示例函數將函數作為參數。



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:

綁定是詞匯作用域賦值(汗,怎么讀怎么別扭--譯者)。每當函數調用時,它就
發生于函數的參數列變量中:形式參數被取代為調用函數時的實際參數。你可以在
程序中隨處綁定變量,就像下面這樣:

? ? ? ?(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,依次類推;然后在它的程序體中執
行語句。let的程序體與函數體的執行規則完全相同。例如:

> (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 內部不能引用
var1,var2等等let正在綁定的成員。
例如(簡而言之,在參數表中,形式參數之間不能互相引用--譯者):

> (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:

如果符號x已經有了一個全局值,會產生一些奇怪的結果:

> (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
等價于

? ? ? ?(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*
語句提供了詞匯作用域。動態
作用域是我們在BASIC里用的那種:如果我們給一個動態作用域變量賦了值,那么
所有對這個變量的訪問都會取得這個值,直到給同一個變量賦了另一個值為止。

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中,動態作用域變量被稱為特化變量 。你可以用
special 語句 defvar
定義一個特化變量。這里有一些詞匯化和動態作用域變量的示例。

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 函數引用一個 regular
(也就是一個詞匯作用域)
變量。因為 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.

在這個例子中,函數 check-special 引用了一個
特化(動態作用域)變量。
因此 check-special 調用臨時發生于特化綁定的 let
內部,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.

方便起見,特化變量以一個 *
開始和結束。特化變量主要用于全局變量,因為
程序員通常期望局部變量使用詞匯作用域,全局變量使用動態作用域。

For more information on the difference between lexical and dynamic
scoping, see _Common LISP: the Language_.

詞匯和動態作用域的更多差異參見《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 函數定義一個數組。aref
函數訪問它的元素。所有元素初始化為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.

數組索引從0開始。

See below for how to set the elements of an array.

以后討論如何設置一個數組的元素。

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:

字符串是包含在雙引號之間的字符串。LISP
用字符串代表一個變長字符數組。
我們可以用一個反斜杠加一個雙引號來表示字符串中的雙引號,兩個反斜杠表示
一個單獨的反斜杠。例如:

? ? ? ?"abcd" has 4 characters
? ? ? ?"\"" has 1 character
? ? ? ?"\\" has 1 character

Here are some functions for dealing with strings:

有一些函數可以用于操作字符串:

> (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 函數可以用于連接任何類型的序列:

> (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 結構類似于C結構或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:

這個示例定義了一個名為 foo
的數據類型,它是一個帶有三個字段的結構。
它同時定義了4個函數用于操作這個數據類型:make-foo,foo-ba,foo-baaz和
foo-quux。第一個函數構造了一個foo類型的新對象,另外三個用于訪問一個
foo類型的對象。以下是這些函數的用法:

> (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
函數可以使用foo結構類型的字段作為關鍵字參數。字段訪問函數以
foo類型的結構為參數,返回對應的字段。

See below for how to set the fields of a structure.

以后討論如何設置一個結構的字段。



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確認語句的時間,自然就會定義一個內存區域。例如,如果x的值是foo類型
的一個結構,(foo-bar
x)定義x中bar字段的值。或者,如果y是一個一維數組,
(aref y 2)定義y的第三個元素。

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
語句用于在內存中將它的第一個參數定位到第二個參數上,并且返回內存
區域的結果值。例如:

> (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是給結構的字段或者數組的元素賦值的唯一方法。

Here are some more examples of setf and related functions.

這里還有一些關于setf和相關函數的示例。

> (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 用自解析符號 nil 來代表 false。任何 nil
之外的其它東西都代表 true。
除非有什么特別的原因,我們總是使用 true
的標準自解析符號 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提供了一個邏輯運算的標準函數集,例如,與、或、非。與和或支持短路算法:
在遇到第一個nil后不再解析右面的參數,而與在遇到第一個t后也不再解析右面的
參數。

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還為條件控制提供了幾個特殊語句。最簡單的是if。if語句的第一個參數決定了
執行第二或第三個參數中的哪一個:

> (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
在它的程序體內依次執行每一條語句,返回最后一個結果。

> (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:

一個沒有 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
允許在程序體內放置任意多的語句。(例如,
(when x a b c) 等價于 (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.

更復雜的條件控制可以用 cond
語句定義實現,它定價于一個 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:

一個 cond 由 symbol
符號和其后的若干條件分支組成,每一個分支是一個
list。
cond
分支的第一個元素是條件;其它的元素(如果有的話)是動作。cond語句查
找第一個條件解析為 true
的分支,執行其響應動作并返回結果值。其它條件不會
被解析,除了這個響應之外的分支也不會執行。例如:


> (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:

如果選定的分支沒有響應動作,cond
返回條件的解析結果。

> (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
巧妙的實現了一個遞歸函數。你可能會有興趣證明它對于所有的整數
x 都少有個終結。(如果你成功了,請發表出來。)

> (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語句將會返回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 中最簡單的迭代結構是 loop:loop
結構反復執行它的程序體直到到達
一個返回語句,例如:

> (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是下一個最簡單的:dolist把一個變量依次綁定到一個列表的各個元素上,
在到達列表結尾時結束。

> (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
永遠不會為nil:C后面的NIL是dolist
返回的,它被讀取-解析-打印循環所打印。

The most complicated iteration primitive is called do. A do statement
looks like this:

更復雜的迭代稱為 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的第一步是指定綁定的變量,它們的初始值,以及如何更新。第二步是指定一
個終止條件和返回值。最后是程序體。do語句像let一樣把它的變量綁定到初始值,
然后校驗終止條件。條件為false時,它重復執行程序體;當條件為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:

前一節中迭代示例里的renturn語句是一個無定位返回的示例,另一個是
return-from,它從包圍它的函數中返回指定值。

> (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:

實際上,return-from
語句可以從任何已命名的語句塊中退出--只是默認情況下
函數是唯一的命名語句塊而已。我們可以用 block
語句自己定義一個命名語句塊。

> (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命名的語句塊中返回。默認情況下循環是nil命名,而
我們可以創建自己的nil標記語句塊。

> (block nil
? ?(return 7)
? ?3)
7

Another form which causes a nonlocal exit is the error form:

另外一個無定位退出語句是 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語句格式化它的參數,然后進入調試器。


Funcall, Apply, and Mapcar

Earlier I promised to give some functions which take functions as
arguments. Here they are:

早先我承諾介紹一些可以將函數作為參數調用函數,它們在這里:

> (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 用它的其它參數調用它的第一個參數。

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很相像,不過它的最后一個參數可以是一個列表;這個列表被看
作是funcall的附加參數。

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的第一個參數必須是一個單參數的函數;mapcar在列表上逐個元素應用該
函數,并將返回值包含如另一個鏈表。

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主要用于第一個參數是變量的場合。例如,搜索引擎把一個啟發式
函數作為參數,在一個狀態描述上應用funcall或者apply。

Mapcar, along with nameless functions (see below), can replace many
loops.

Mapcar配合匿名函數(后面介紹),可以取代很多循環。

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.

如果你只是想創建一個臨時函數,并不想給它一個命名,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的組合可以取代很多循環,例如,如下的兩個語句是等價的:

> (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提供兩種主要的排序:排序和穩定排序。

> (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的第一個參數是一個列表,第二個是一個比較函數。sort函數不保證穩定性:
如果這里有a和b兩個元素,(and (not (< a b)) (not (< b
a))),sort可能會改
變它們的位置。stable-sort(穩定排序)與sort非常像,不過它確保兩個相等
的元素在排序后的列表中的順序與排序前列表中的順序相同。

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可能會破壞它的參數,如果原始序列對我們很重要,最好使用copy-list
或copy-seq函數創建一個副本。


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.

關于相等,LISP有很多不同的觀點。數值相等意味著=。兩個符號當且僅當他們完全
一樣時相同。同一個列表的兩個副本不相同,但是它們相等。

> (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代表相等,它對于符號表示相同,對于數值表示=。

> (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謂詞對于符號和數值是相等。當且僅當兩個 conse
的car和cdr都相等時它們
才是相等的。當且僅當兩個結構是同類型而且各字段都相等時它們相等。



Some Useful List Functions

These functions all manipulate lists.

這些函數都用來操作列表。

> (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都允許各個參數包含不匹配的元素
--例如,(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都可以接受一個:test關鍵
字參數;默認情況下,它們是等價的。

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文件時總會自動進入LISP模式,
不過如果我們的Emacs沒有成功進入這個狀態,可以通過輸入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下運行LISP:先確保在我們的私人路徑下可以運行一個叫
"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發送先前的LISP代碼,做其它
很酷的事情;在LISP模式下的任何緩沖輸入 C-h
m可以得到進一步的信息。

Actually, you don't even need to make a link. Emacs has a variable
called inferior-lisp-program; so if you add the line

實際上,我們甚至不需要建立鏈接。Emacs有一個變量叫
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就會知道在你輸入 M-x
run-lisp時去哪里尋找
CLISP。

總結

以上是生活随笔為你收集整理的Lisp入门教程的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。