Common Lisp 符号中文文档

Table of Contents

1 函数/宏

1.1 +

(+ &rest numbers)

加法。

CL-USER> (+ 1 1)
2
CL-USER> (+ 1 2 3)
6

1.2 -

(- number &rest more-numbers)

减法。

CL-USER> (- 2 1)
1
CL-USER> (- 10 8 1) ; 等同 10 - 8 - 1
1
CL-USER> (- 2) ; 如果只有一个数字,就取它的负数
-2

1.3 *

( &rest numbers)*

乘法。

CL-USER> (* 3 2 5)
30

1.4 /

(/ number &rest more-numbers)

除法。

CL-USER> (/ 3)
1/3
CL-USER> (/ 3 2) ; 无法整除时返回有理数
3/2
CL-USER> (/ 10 5)
2

1.5 1+

(1+ number)

返回 number 加 1 后的值。

CL-USER> (1+ 1.0)
2.0
CL-USER> (1+ 10)
11

1.6 1-

(1- number)

返回 number 减 1 后的值。

CL-USER> (1- 10)
9

1.7 and

(and &rest forms)

所有 form 计算如果都不为 nil,返回最后个 form 的值,否则返回 nil。

CL-USER> (and 1 2 3)
3
CL-USER> (and 1 2 nil)
NIL

1.8 atom

(atom object)

谓词函数,判断 object 是否是一个原子,术语“原子”解释请见[这里](/cl/term)

CL-USER> (atom "123")
T
CL-USER> (atom '1)
T
CL-USER> (atom "1")
T
CL-USER> (atom #\1)
T
CL-USER> (atom 1)
T
CL-USER> (atom nil)
T
CL-USER> (atom '(1 2 3)) ; 非空列表不是原子
NIL

1.9 arrayp

(arrayp object)

谓词函数,判断 object 是否是数组

CL-USER> (defvar x (make-array 10 :initial-element 1))
X
CL-USER>  (arrayp x)
T

1.10 aref

(aref array &rest subscripts)

访问数组元素。参数 subscripts 是有效的下标,如果是多维数组,subscripts 应该有多个下标值,具体看示例。

;;; 访问一维数组中下标0和下标1的元素

CL-USER> (aref #(A B C) 0)
A
CL-USER> (aref #(A B C) 1)
B

;;; 访问二维数组
CL-USER> (defvar a-rank-array (make-array '(2 2))) ; 创建一个二维数组
A-RANK-ARRAY
CL-USER> (aref a-rank-array 0 1)
0
CL-USER> (setf (aref a-rank-array 0 1) 1)
1
CL-USER> a-rank-array
#2A((0 1) (0 0))

由于 aref 是直接指向数组元素的内存地址,所以借助它可修改数组元素:

CL-USER> (defvar a-array #(1 2 3))
A-ARRAY
CL-USER> (setf (aref a-array 2) 'A)
A
CL-USER> a-array
#(1 2 A)

1.11 assoc

(assoc item alist &key key test test-not)

访问一个 association list 结构,association list 结构每个元素都是一个嵌套列表。

CL-USER> (assoc 'a '((a 1) (b 2)))
(A 1)
CL-USER> (assoc "a" '(("a" 1) ("b" 2)) :test #'equal) ; 指定 :test 参数
("a" 1)

1.12 character

(character obj)

返回对象的字符表示。

CL-USER> (character #\a)
#\a
CL-USER> (character "a") ; 字符串只能包含一个字符
#\a
CL-USER> (character "abc") ; 字符串包含多个字符会出错
CL-USER> (character 'a)
#\A
CL-USER> (character 100) ; 不能是数字

注意,在 CLISP 实现里,如果参数为数字就返回对应的 ASCII 字符:

[1]> (character 97)
#\a
[2]> (character 0)
#\Null

1.13 char-code

(char-code character)

返回字符对应的 ASCII 码。

CL-USER> (char-code #\a)
97
CL-USER> (char-code #\A)
65

1.14 coerce

(coerce ojb output-type)

转换 obj 的类型。

如果 obj 的类型和 output-type 一样的,就原样返回:

CL-USER> (coerce 1 'integer)
1
CL-USER> (coerce "1" 'string)
"1"

把 obj 转换成序列:

CL-USER> (coerce "hello world" 'simple-vector)
#(#\h #\e #\l #\l #\o #\  #\w #\o #\r #\l #\d)
CL-USER> (coerce "hello world" 'list)
(#\h #\e #\l #\l #\o #\  #\w #\o #\r #\l #\d)
CL-USER> (coerce "hello world" 'array)
"hello world"

字符列表转成字符串:

CL-USER> (coerce '(#\h #\e #\l #\l #\o) 'string)
"hello"

转换成字符:

CL-USER> (coerce 'a 'character)
#\A
CL-USER> (coerce 'hello 'character) ; 错误,obj 必须是单字符
CL-USER> (coerce :a 'character)
#\A

数字类型转换:

CL-USER> (coerce 1.23 'complex) ; 转换成复数类型
#C(1.23 0.0)'
CL-USER> (coerce 1 'float) ; 转换成浮点数类型
1.0

根据符号名转换成已绑定的函数。注意必须是函数,不能用在宏上:

CL-USER> (coerce '+ 'function)
#<FUNCTION +>
CL-USER> (funcall (coerce '+ 'function) 1 1) ; 调用返回的函数类型
2
CL-USER> (coerce "+" 'function) ; 错误,名字不能是字符串

1.15 cons

(cons se1 se2)

创建一个 cons cell。se1 是左指针,se2 是右指针。

CL-USER> (cons 1 2) ; 左边指针指向存储了“1”的内存地址,右边指针指向存储了“2”的内存地址
(1 . 2)
CL-USER> (cons 1 nil)
(1)
CL-USER> (cons 1 (cons 2 nil))
(1 2)

1.16 decf

(decf place delta)

对 place 指向的内存位置做减法操作。delta 是减去的值,默认是1,也可以是一个表达式计算结果。

CL-USER> (defvar a-value 10)
A-VALUE
CL-USER> (decf a-value) ; 默认减1
9
CL-USER> (decf a-value (+ 1 1)) ; 对象的值减2
7

1.17 defmethod

(defmethod name &rest args)

定义方法,可以根据传入参数的类型动态调用。

(defmethod add ((a number) (b number))
  (+ a b))

(defmethod add ((a list) (b list))
  (append a b))

调用:

CL-USER> (add 1 1)
2
CL-USER> (add '(1 2) '(3 4))
(1 2 3 4)

1.18 defconstant

(defconstant name value &optional doc)

定义一个常量。Common Lisp 里常量名一般用“+”包围,最好是遵守这个命名约定。

CL-USER> (defconstant +a-constant+ 10)
+A-CONSTANT+
CL-USER> (defconstant +a-constant+ 10 "定义一个常量")
+A-CONSTANT+
CL-USER> +a-constant+
10

1.19 describe

(describe obj &optional output)

查看对象的信息。

CL-USER> (describe 'funcall) ; 查看 funcall 函数的信息
COMMON-LISP:FUNCALL
  [symbol]

FUNCALL names a compiled function:
  Lambda-list: (FUNCTION &REST ARGUMENTS)
  Declared type: (FUNCTION ((OR FUNCTION SYMBOL) &REST T) *)
  Documentation:
    Call FUNCTION with the given ARGUMENTS.
  Known attributes: call, unwind, any
  Source file: SYS:SRC;CODE;EVAL.LISP

1.20 do

(do varlist endlist &body body)

循环。

参数 varlist 用来定义变量,可指定初始值以及步长:

(i) ; 定义变量 i
(i 0) ; 定义变量 i,并初始为 0
(i 0 (+1 i)) ; 定义变量i并初始为 0,每次循环都会调用 +1 进行自加操作

endlist 指定循环结束的条件,以及返回值:

((> i 100)) ; 结束条件为 i 大于 100
((> i 100) i) ; 指定 do 循环的返回值 i

例:从 1 加到 100,过程中打印 i 的值,最后表达式返回相加结果:

(do ((i 0 (1+ i))
     ;; 变量n作为累加器
     (n 0 (+ n i)) )
    ((> i 100) n)
  (print i))

1.21 dolist

(dolist (var list &optional result) &body body)

迭代一个 list 对象。

  • var:参数存储每次取到 list 元素的值。
  • list:遍历的对象。
  • result:可选参数,指定表达式。
(dolist (i '(1 2 3 4 5))
  (print i))

1.22 dotimes

(dotimes (var count &optional result) &body body)

按次数循环。

(dotimes (i 100 i)
  (print i))

1.23 eq

(eq obj1 obj2)

比较 obj1 和 obj2 是不是同个对象,或者指向同个对象,是则返回t,否则返回 nil。

CL-USER> (defvar hello "hello world")
HELLO
CL-USER> (defvar a hello)
A
CL-USER> (defvar b hello)
B
CL-USER> (eq a b)
T
CL-USER> (defvar c a)
C
CL-USER> (eq a c)
T
CL-USER> (eq b c)
T
CL-USER> c
"hello world"
CL-USER> (defvar d "hi")
D
CL-USER> (eq d c)
NIL
CL-USER> (defvar a-list '(a b a))
A-LIST
CL-USER> (eq (car a-list) (caddr a-list))
T

1.24 eql

(eql obj1 obj2)

判断 obj1 和 obj2 是否相等,规则:

  1. (eq obj1 obj2) 为 t,那 eql 也返回 t。
  2. obj1 和 obj2 是两个相同类型的数字,并且值也相等。
  3. obj1 和 obj2 是两个相同的字符。
CL-USER> (defvar a 1)
A
CL-USER> (defvar b a)
B
CL-USER> (eql a b) ; 指向相同对象
T
CL-USER> (eql 1 1) ; 相同类型、相同值的数字
T
CL-USER> (eql 1 1.0) ; 类型不同,所以返回 nil
NIL
CL-USER> (eql #\a #\a) ; 相同的字符
T
CL-USER> (defvar a-list '(1 2 3))
A-LIST
CL-USER> (eql a-list '(1 2 3)) ; 值相同,但并不是一个对象,所以返回 nil
NIL

1.25 euqal

(euqal x y)

判断 x 和 y 是否相等,比 eql 判断得更深入一些。

CL-USER> (equal 'a 'a) ; 符号判断和 eq 的规则一样
T
CL-USER> (equal 100 100) ; 数字判断和 eql 规则一样
T
CL-USER> (equal #\a #\a) ; 字符判断和 eql 规则一样
T

;;; 判断 cons
CL-USER> (equal '(1 2 3) '(1 2 3)) ; 元素相同也为 t
T
CL-USER> (equal '(1 2 3) '(3 2 1)) ; 元素顺序必须一致才返回 t
NIL

;;; 判断 array
;;; 只有字符串和 bit-vector 才能判断是否相等
CL-USER> (equal "test" "test")
T
CL-USER> (equal "Test" "test") ; 字符串比较时不会忽略大小写
NIL
CL-USER> (equal #*1001 #*1001)
T
CL-USER> (equal #(1 2 3) #(1 2 3)) ; 其他 array 无法比较
NIL

CL-USER> (equal #p"/tmp/test" #p"/tmp/test") ; 判断 pathname 是否相等
T

1.26 equalp

(equalp x y)

比较两个对象是否相等。比 equal 判断得还要深入一些。

CL-USER> (equalp "Test" "test") ; 字符串比较会忽略大小写
T
CL-USER> (equalp #(1 2 3) #(1 2 3)) ; 比较 array 是否相等
T
CL-USER> (equalp #\a #\a) ; 字符比较
T
CL-USER> (equalp 1 1) ; 数字比较
T
CL-USER> (equalp 1 1.0) ; 整数和浮点数比较
T
CL-USER> (equalp '(1 2 3) '(1 2 3)) ; cons 比较
T

;;; 比较结构体
CL-USER> (make-my-info :name "lu4nx" :blog "shellcodes.org")
#S(MY-INFO :NAME "lu4nx" :BLOG "shellcodes.org")
CL-USER> (defvar a (make-my-info :name "lu4nx" :blog "shellcodes.org"))
A
CL-USER> (defvar b (make-my-info :name "lu4nx" :blog "shellcodes.org"))
B
CL-USER> (equalp a b)
T
CL-USER> (equalp a (make-my-info :name "luanx" :blog "shellcodes.org")) ; 元素不相等返回 nil
NIL

;;; 比较 hash 表
CL-USER> (defvar x (make-hash-table))
X
CL-USER> (defvar y (make-hash-table))
Y
CL-USER> (equalp x y) ; 两个 hash 表都是空元素,所以相等
T
CL-USER> (setf (gethash :name x) "lu4nx") ; 给其中一个 hash 表设置键值后再比较
"lu4nx"
CL-USER> (equalp x y)
NIL

1.27 ensure-directories-exist

(ensure-directories-exist path &key verbose (mode 511))

创建一个目录。path 指定的路径一定要以“/”结尾。

CL-USER> (ensure-directories-exist "/tmp/test-function/")
"/tmp/test-function/"
T
CL-USER> (ensure-directories-exist "/tmp/test-function/a") ; 如果路径不以“/”结尾,目录 a 是不会被创建的
"/tmp/test-function/a"
NIL

1.28 fboundp

(fboundp name)

判断符号是否绑定了函数。

CL-USER> (fboundp '+)
T
CL-USER> (fboundp 'a)
NIL

1.29 found-symbol

(find name &optional package)

从指定包里查找符号,默认从 *package* 里查找。

CL-USER> (defvar hello "hello")
HELLO
CL-USER> (find-symbol "HELLO") ; 字符串要大写
HELLO
CL-USER> (find-symbol "FUNCALL" :cl) ; 从 CL 包里查找 funcall
FUNCALL
CL-USER> (funcall (find-symbol "+" :cl) 1 1) ; 直接调用返回的函数符号
2

1.30 force-output

(force-output &optional (stream *standard-output*))

在 stream 指向的缓存取的内容为空时不等待。

下面这段代码在 SBCL 下执行时,只有输入了内容才会看到提示字符“say:”:

(format t "say:")
(read)

注:CLISP 会先打印字符串,再等待输入,等同默认加了 force-output 操作。

force-output 可以在等待输入之前就看到输出的字符串:

(format t "say:")
(force-output)
(read)

1.31 incf

(incf place delta-form)

对 delta-form 形式进行求值,并把求值结果加到 place 上,delta-form 默认为1。

注意:incf 是有副作用的,它直接修改 place 的值,而不是返回一个新值

(incf n) 等同于 (setf n (1+ n))

(incf n 10) 等同于 (setf n (+ n 10))

CL-USER> (defvar a 1)
A
CL-USER> (incf a)
2
CL-USER> a
2
CL-USER> (incf a 10)
12
CL-USER> (incf a (+ 1 1))
14
CL-USER> a
14

1.32 input-stream-p

(input-stream-p stream)

判断 stream 是否是输入流对象。

CL-USER> (input-stream-p *standard-input*)
T
CL-USER> (input-stream-p *standard-output*)
NIL

1.33 list

(list &rest args)

创建一个列表。

CL-USER> (list 1 2 3)
(1 2 3)
CL-USER> (list 1 2 3 'a 'b 'c)
(1 2 3 A B C)

1.34 listp

(listp object)

谓词函数,判断 object 是否是 list 对象,是的话返回 t,否则返回 nil

CL-USER> (listp '(1 2 3))
T
CL-USER> (listp 123)
NIL

1.35 list-all-packages

(list-all-packages)

列出当前镜像中所有的包

1.36 loop

(loop &rest keywords-and-forms)

loop 宏较复杂,请在这里查看更多示例。

1.37 long-site-name

(long-site-name)

获得机器信息。不同的 Common Lisp 实现返回的信息不一致。

;; for CLISP
[1]> (long-site-name)
"Linux lx-pc 4.3.5-300.fc23.x86_64 #1 SMP Mon Feb 1 03:18:41 UTC 2016 x86_64 x86_64 x86_64 GNU/Linux"

;; for Allegro CL
CG-USER(1): (long-site-name)
"LU4NX-PC"

;; for LispWorks
CL-USER 1 > (long-site-name)
"Unknown"

;; for SBCL
CL-USER> (long-site-name)
NIL

1.38 machine-type

(machine-type)

获得处理器架构信息。

CL-USER> (machine-type)
"X86-64"

1.39 machine-version

(machine-version)

获得处理器信息。

CL-USER> (machine-version)
"Intel(R) Core(TM) i7-3520M CPU @ 2.90GHz"

1.40 machine-instance

(machine-instance)

获得 Common Lisp 运行的平台信息,不同的实现返回的结果不一样,比如 SBCL 返回主机名:

CL-USER> (machine-instance)
"lx"

1.41 macroexpand

(macroexpand form &optional env)

展开全部的宏。

CL-USER> (macroexpand '(dotimes (i 10) (print i)))
(BLOCK NIL
  (LET ((I 0))
    (DECLARE (TYPE UNSIGNED-BYTE I))
    (TAGBODY
      (GO #:G682)
     #:G681
      (TAGBODY (PRINT I))
      (PSETQ I (1+ I))
     #:G682
      (UNLESS (>= I 10) (GO #:G681))
      (RETURN-FROM NIL (PROGN NIL)))))
T

1.42 macroexpand-1

(macroexpand-1 form &optional env)

展开宏表达式。macroexpand-1 只展开一层宏,而不是全部展开。

CL-USER> (macroexpand-1 '(dotimes (i 10) (print i)))
(DO ((I 0 (1+ I))) ((>= I 10) NIL) (DECLARE (TYPE UNSIGNED-BYTE I)) (PRINT I))
T

也可以把 macroexpand-1 用作判断表达式是否是宏,如果是宏就返回 t,否则返回 nil:

1.43 make-string

(make-string count &key (element-type 'character) initial-element)

返回包含重复了 count 次的参数 initial-element 的字符串。

CL-USER> (make-string 100 :initial-element #\a)
"aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa"

注意:如果 initial-element 不指定值,各个 Common Lisp 实现对返回的结果是不一样的。

1.44 short-site-name

(short-site-name)

获得机器信息。不同的 Common Lisp 实现返回的信息不一致。

;; for CLISP,返回主机名
[1]> (short-site-name)
"lx"

;; for Allegro CL
CG-USER(1): (short-site-name)
"LU4NX-PC"

;; for LispWorks
CL-USER 1 > (short-site-name)
"Unknown"

;; for SBCL
CL-USER> (short-site-name)
NIL

1.45 string-left-trim

(string-left-trim char-bag string)

从 string 左边开始将 char-bag 指定的内容剔除掉,如果 string 的起始内容和 char-bag 不一样,就原样返回,否则返回一个新的字符串。

CL-USER> (string-left-trim "Hi" "Hi,girl. Hi,boy.")
",girl. Hi,boy." ; 只会剔除第一次匹配到的

1.46 string-right-trim

(string-right-trim char-bag string)

同 string-left-trim 一样,只是方向是从右边。

CL-USER> (string-right-trim "boy." "Hi,girl. Hi,boy.")
"Hi,girl. Hi,"

1.47 string-trim

(string-trim char-bag string)

从 string 左边或右边开始将 char-bag 指定的内容剔除掉。

CL-USER>  (string-trim "hello" "hello, world")
", world"
CL-USER>  (string-trim "world" "hello, world")
"hello, "

1.48 software-type

(software-type)

返回操作系统平台信息,SBCL 输出:

CL-USER> (software-type)
"Linux"

1.49 software-version

(software-version)

返回平台的版本号,SBCL 输出:

CL-USER> (software-version)
"4.3.5-300.fc23.x86_64"

1.50 shiftf

(shiftf &rest args)

从右向左重新赋值:将最后一个表达式的值赋值给倒数第二个的 place,倒数第二个 place 的值赋值给倒数第三个 place,依次类推。

CL-USER> (defvar a 1)
A
CL-USER> (defvar b 2)
B
CL-USER> (defvar c 3)
C
CL-USER> (shiftf a b c 4)
1
CL-USER> a
2
CL-USER> b
3
CL-USER> c
4
CL-USER> ;;;; 第二个例子:修改列表
CL-USER> (defvar x '(a b c))
X
CL-USER> (defvar y 'd)
Y
CL-USER> (defvar z 0)
Z
CL-USER> (shiftf z (nth 1 x) y)
0
CL-USER> z
B
CL-USER> x
(A D Z)
CL-USER> y
D

1.51 substitute

(substitute new old seq &rest args &key from-end (test #'eql) test-not (start 0) count end key)

替换序列中的内容。

CL-USER> (substitute #\a #\b "abcd")
"aacd"
CL-USER> (substitute 10 1 #(1 2 3 4 5))
#(10 2 3 4 5)

1.52 minusp

(minusp number)

如果number小于0,返回T

CL-USER> (minusp 1)
NIL
CL-USER> (minusp 0)
NIL
CL-USER> (minusp -1)
T

1.53 mismatch

(mismatch seq1 seq2 &rest args &key from-end (test '#eql) test-not (start1 0) end1 (start2 0) end2 key)

返回两个向量首次不同的位置。

CL-USER> (mismatch "http://www.shellcodes.org" "http://")
7

1.54 multiple-value-prog1

(multiple-value-prog1 values-form &rest forms)

执行多个表达式,并把第一个表达式的执行结果作为返回结果。

CL-USER> (multiple-value-prog1
 (1+ 1)
 (print "a")
 (print "b"))

"a"
"b"
2

1.55 null

(null object)

判断 object 是否为 nil

CL-USER> (null nil)
T
CL-USER> (null '())     ; 空列表等同于 nil
T
CL-USER> (null 1)
NIL

1.56 numberp

(numberp object)

谓词函数,判断 object 是否是 number,是的话返回 t,否则返回 nil

CL-USER> (numberp 123)
T
CL-USER> (numberp 123.0)
T
CL-USER> (numberp 0.1)
T
CL-USER> (numberp "1")
NIL
CL-USER> (numberp 1/2)
T

1.57 notany

(notany pred seq1 &rest more-seqs)

参数 pred 是一个谓词函数,提供一个或多个序列用作判断,如果全部不为真,notany 返回 T。

如果只提供一个序列,那么序列中的每个元素会被应用到函数上:

CL-USER> (notany #'evenp '(1 2 3 4))
NIL
CL-USER> (notany #'evenp '(1 3 5 7))
T

如果提供多个序列,会同时传递多个参数给函数,所以函数需要支持指定参数数量才行:

CL-USER> (notany #'equal '(1 3 5 7) '(1 3 5 7))
NIL
CL-USER> (notany #'equal '(1 3 5 7) '(2 4 6 8)) ; 全部不相等
T

1.58 nth-value

(nth-value n form)

form 是一个返回多值的表达式,参数 n 用来指定获得哪一个值,n 从 0 开始计数。

CL-USER> (nth-value 1 (values 'value1 "value2"))
"value2"
CL-USER> (nth-value 0 (values 'value1 "value2"))
VALUE1

1.59 nthcdr

(nthcdr n list)

对 list 指定 n 次“cdr“。

CL-USER> (nthcdr 2 '(1 2 3)) ; 等同于 (cdr (cdr '(1 2 3)))
(3)

1.60 output-stream-p

(output-stream-p stream)

判断 stream 是否是一个可输出的流对象,是则返回 t,否则返回 nil。

CL-USER> (output-stream-p *standard-input*)
NIL
CL-USER> (output-stream-p *standard-output*)
T

1.61 pairlis

(pairlis keys data &optional alist)

构造 alist。

CL-USER> (pairlis '(a b c) '(1 2 3))
((C . 3) (B . 2) (A . 1))
CL-USER> (pairlis '(a b c) '(1 2 3) '((x 1) (y 2) (z 3))) ; 指定最后一个 alist 参数
((C . 3) (B . 2) (A . 1) (X 1) (Y 2) (Z 3))

1.62 plusp

(plusp number)

如果 number 大于 0,返回 T:

CL-USER> (plusp 1)
T
CL-USER> (plusp 0)
NIL
CL-USER> (plusp -1)
NIL

1.63 progn

(progn &rest forms)

执行多个表达式,并将表达式最后个值作为返回值。

Q:什么时候该用 progn,什么时候用 block?

A:如果需要突然退出,使用 block,其他时候则用 progn。

CL-USER> (progn (print 1) (print 2) 3)

1
2
3

1.64 psetf

(psetf &rest pairs)

给多个 pair 分配新的值。

CL-USER> (defvar x '(1 2 3))
X
CL-USER> (defvar y '(4 5 6))
Y
CL-USER> (psetf (car x) 'one (car y) 'four)
NIL
CL-USER> x
(ONE 2 3)
CL-USER> y
(FOUR 5 6)
CL-USER> (psetf x 1 y 2)
NIL
CL-USER> x
1
CL-USER> y
2

1.65 parse-integer

(parse-integer string &key (start 0) end (radix 10) junk-allowed)

将字符串转换成数字。这个函数会返回两个值,第一个值是转换结果,第二个值是转换的字符数。

CL-USER> (parse-integer "123")
123
3
CL-USER> (parse-integer "1101" :radix 2) ; radix 指定进制,这里转换二进制
13
4

1.66 rename-file

(rename-file file new-name)

重命名文件

CL-USER> (rename-file #p"/tmp/old" "new")
#P"/tmp/new"
#P"/tmp/old"
#P"/tmp/new"

1.67 rotatef

(rotatef &rest args)

旋转式交换变量的值

注意:rotatef 有副作用,是直接修改符号的值

CL-USER> (defvar a 1)
CL-USER> (defvar b 2)
CL-USER> (defvar c 3)
CL-USER> a
1
CL-USER> b
2
CL-USER> c
3
CL-USER> (rotatef a b c)
NIL
CL-USER> a
2
CL-USER> b
3
CL-USER> c    ; 因为是轮旋交换变量,c 是最后个变量,所以应该取第一个变量的值
1

技巧1:交换两个变量的值:

CL-USER> (defvar var1 1)
VAR1
CL-USER> (defvar var2 2)
VAR2
CL-USER> (rotatef var1 var2)
NIL
CL-USER> var1
2
CL-USER> var2
1

技巧2:交换列表中的值:

CL-USER> (defvar a-list '(a 1 b 2 c 3))
A-LIST
CL-USER> (rotatef (nth 0 a-list) (nth 1 a-list))
NIL
CL-USER> a-list
(1 A B 2 C 3)

1.68 set

(set symbol value)

改变 symbol 的值。symbol 必须加单引号(用 setq 可以省略单引号)。

CL-USER> (set 'a 1)
1
CL-USER> a
1

1.69 string-capitalize

(string-capitalize stirng &key (start 0) end)

将字符串中英文单词首字母大写。

CL-USER> (string-capitalize "hello world")
"Hello World"

1.70 svref

(svref vector index)

svref 用来快速索引向量(vector)。

CL-USER> (svref #(1 2 3 4 5 6) 3)
4

1.71 symbol-value

(symbol-value symbol)

返回符号对应的值。

CL-USER> (defvar hi "hi")
HI
CL-USER> (symbol-value 'hi)
"hi"

1.72 time

(time form)

测试一个表达式执行需要花费多长时间。

CL-USER> (time (sleep 10))
Evaluation took:
  10.0000 seconds of real time
  0.012742 seconds of total run time (0.009542 user, 0.003200 system)
  0.13% CPU
  28,934,402,420 processor cycles
  68,336 bytes consed

1.73 truncate

(truncate number &optional divisor)

返回浮点数整数和小数部分。参数 divisor 是除数,默认为 1。

CL-USER> (truncate pi)
3
0.14159265358979312d0
CL-USER> (truncate pi 3) ; 除数改为 3
1
0.14159265358979312d0

1.74 trace

(trace &rest specs)

跟踪函数调用。

比如定义一个斐波那契数列:

(defun fab (n)
  (cond ((equal 0 n) 0)
        ((equal 1 n) 1)
        (t (+ (fab (- n 1))
              (fab (- n 2))))))

然后对 fab 函数进行调用跟踪:

CL-USER> (trace fab)

调用 trace 函数后再执行它,就可以看到函数调用过程:

CL-USER> (fab 5)
  0: (FAB 5)
    1: (FAB 4)
      2: (FAB 3)
        3: (FAB 2)
          4: (FAB 1)
          4: FAB returned 1
          4: (FAB 0)
          4: FAB returned 0
        3: FAB returned 1
        3: (FAB 1)
        3: FAB returned 1
      2: FAB returned 2
      2: (FAB 2)
        3: (FAB 1)
        3: FAB returned 1
        3: (FAB 0)
        3: FAB returned 0
      2: FAB returned 1
    1: FAB returned 3
    1: (FAB 3)
      2: (FAB 2)
        3: (FAB 1)
        3: FAB returned 1
        3: (FAB 0)
        3: FAB returned 0
      2: FAB returned 1
      2: (FAB 1)
      2: FAB returned 1
    1: FAB returned 2
  0: FAB returned 5
5

trace 函数如果不跟参数,列出当前被 trace 过的函数:

CL-USER> (trace)
(FAB)

用 untrace 函数可以解除跟踪。

1.75 type-of

(type-of object)

查看对象的类型

CL-USER> (type-of 1)
BIT
CL-USER> (type-of 12345)
(INTEGER 0 4611686018427387903)
CL-USER> (type-of "abc")
(SIMPLE-ARRAY CHARACTER (3))
CL-USER> (type-of #\a)
STANDARD-CHAR
CL-USER> (type-of '(1 2 3))
CONS

1.76 unintern

(unintern symbol &optional package)

将一个符号从包中移除。

CL-USER> (defvar a 1)
A
CL-USER> a
2
CL-USER> (unintern 'a)
T
CL-USER> a ; The variable A is unbound.

1.77 unwind-protect

(unwind-protect protected &body cleanup)

unwind-protect 可以为表达式提供一个“清理函数”,保证无论发生什么异常都会去执行。如:

(defun hello ()
  (unwind-protect
       (error "hello")
    (print "exit")))

(print "exit") 这句话一定在最后会被执行。Common Lisp 中常见的 with- 开头的宏基本上都是封装了 unwind-protect 的,比如我们展开 with-open-file 看看:

CL-USER> (macroexpand '(with-open-file (f "/etc/passwd")))

(LET ((F (OPEN "/etc/passwd")) (#:G930 T))
  (UNWIND-PROTECT (MULTIPLE-VALUE-PROG1 (PROGN) (SETQ #:G930 NIL))
    (WHEN F (CLOSE F :ABORT #:G930))))
T

1.78 values

(values &rest values)

返回多个值。

CL-USER> (values 'value1 'value2)
VALUE1
VALUE2

1.79 vector

(vector &rest objs)

创建一个向量。

CL-USER> (vector 1 2 3)
#(1 2 3)
CL-USER> (vector 1 2 3 'a 'b 'c)
#(1 2 3 A B C)

#(…) 语法和 vector 函数等同:

CL-USER> #(1 2 3)
#(1 2 3)

1.80 with-standard-io-syntax

(with-standard-io-syntax &body body)

在执行 body 的表示式时,将一些会影响 I/O 输出的变量恢复成默认值,防止动态绑定的影响。

(let ((a '(1 2 3 4 5))
      ; *print-length* 设置打印 list 时显示的元素数量
      (*print-length* 3))
    (print a) ; 输出:(1 2 3 ...)
    (with-standard-io-syntax
      ; 输出:(1 2 3 4 5),在 with-standard-io-syntax 代码块中,*print-length* 将恢复成默认值
      (print a)))

1.81 write-to-string

(write-to-string obj)

返回对象的字符打印形式。

CL-USER> (write-to-string '(1 2 3))
"(1 2 3)"
CL-USER> (write-to-string 123) ; 可以作为数字和字符串的转换
"123"
CL-USER> (write-to-string (make-hash-table))
"#<HASH-TABLE :TEST EQL :COUNT 0 {10035DC8B3}>"
CL-USER> (write-to-string #'and)
"#<CLOSURE (:MACRO AND) {1000BDFB8B}>"
CL-USER> (write-to-string #(1 2 3))
"#(1 2 3)"

1.82 zerop

(zerop number)

谓词函数,如果 number 等于 0,返回 T

CL-USER> (zerop 0)
T
CL-USER> (zerop 1)
NIL

2 全局常量/变量

2.1 常量

常量 用途
pi 具体的精度取决于 Common Lisp 实现。
most-negative-fixnum fixnum 类型允许的最小值。
most-positive-fixnum fixnum 类型允许的最大值。

2.2 变量

2.2.1 *print-array*

如果值为 t,打印数组时会打印具体内容,否则只打印数组信息。

CL-USER> (setf *print-array* nil)
NIL
CL-USER> (print #(1 2 3))

#<(SIMPLE-VECTOR 3) {10031B641F}>
#<(SIMPLE-VECTOR 3) {10031B641F}>
CL-USER> (setf *print-array* t)
T
CL-USER> (print #(1 2 3))

#(1 2 3)
#(1 2 3)