Emacs: Elisp 手册学习手稿

使用 lisp 模式 M-x lisp-interaction-mode 或 Ielm 模式 M-x inferior-emacs-lisp-mode

Lisp 数据类型

参考:Lisp Data Types

(message "%s" emacs-build-time)
"(26937 51891 419712 0)"
(message "%s" emacs-version)
"30.2"
(message "%s" emacs-major-version)
"30"
(message "%s" emacs-minor-version)
"2"
(prin1 emacs-repository-version)
nilnil
(current-buffer)
#<buffer *scratch*>

(let ((a  (list 1)))
  (setcdr a a))
(1 . #0)
(setq a (list 1))
(1)
(cdr a)
nil
()

;;; 编程类型
;;;; 整数类型
(fixnump 1)
t
(bignump 1)
nil
(princ most-negative-fixnum)
-2305843009213693952-2305843009213693952
(prin1 most-positive-fixnum)
23058430092136939512305843009213693951

(> most-positive-fixnum 99999)
t
-1
-1
1
1
1.
1
+1
1

;;;; 浮点类型
;; 浮点数看作一个分数与一个 10 的幂的组合
1500.0
+15e2
15.0e+2
+1500000e-3
;;;; 字符类型
?A
65
?B
66
?a
97
?\(
40
?\\
92
?\a ; C-g
7
?\b ; DEL
8
?\t
?\n
?\s ; 空格符
32
?\  ; 多加一个空格,以便与后续文本分隔
32

?\r
13
?\+ ; 等价 ?+ ; 没有特殊转义含义的字符前面加反斜杠是允许的
;; ()[]\;" 前必须加反斜杠。 |'`#., 前建议加
?\|
124
?|
124
?\`
96
;; 非 ASCII
?\N{LATIN SMALL LETTER A WITH GRAVE} ; 非 ASCII,如有名称。名称中的空格可以替换为任意非空空白序列(如换行)
224
?à
224
?\N{U+E0}
224
?\u00e0
224
?\U000000e0
224
?\340 ; 八进制
224
?\101 ; A
65
?\001 ; C-a
;; 控制字符
?\^I  ; C-i
9
?\^i  ; C-i
9
?\C-i ; C-i
9
?\C-b ; C-b
2

ELISP> ?\^? ; DEL 字符视为 ?
127
 (#o177, #x7f, ?\C-?)
ELISP> ?\C-?
127
 (#o177, #x7f, ?\C-?)

;; META 字符语法
?\M-A ; meta 在高位
134217793

ELISP> ?\M-\101
134217793
 (#o1000000101, #x8000041)
ELISP> ?A
65
 (#o101, #x41, ?A)
ELISP> ?\M-\C-b ; C-M-b
134217730
 (#o1000000002, #x8000002)
ELISP> ?\C-\M-b
134217730
 (#o1000000002, #x8000002)
ELISP> ?\M-\002
134217730
 (#o1000000002, #x8000002)
ELISP> ?\C-b
2
 (#o2, #x2, ?\C-b
;; 其他字符修饰符
?\C-\S-o ; Shift-Ctrl-o
33554447
?\S-\C-o
33554447
;; hyper \H- ; super \s- ; alt \A-
?\H-\M-\A-x ; Alt-Hyper-Meta-x
155189368

;;;; 符号类型
1+                  ; 符号名称为 ‘1+                    ;   (而非 ‘+1’ — 后者是整数)。
\+1                 ; 符号名称为 ‘+1                    ;   (可读性较差)。
\(*\ 1\ 2\)         ; 符号名称为 ‘(* 1 2)’ (更差的名称)。

;;;; 序列类型
;; list
;; array: string, vector, char-table, bool-vector

(length "aa")
2
(length '(aa))
1
(length ["aa" "bb"])
2
;; 一般,不可能两次读取到同一序列对象;空列表除外,() === nill

;;;; Cons 单元与列表类型
;; cons cell:是包含两个存储位的对象,分别称为 CAR 位和 CDR 位
;; list:是由一系列 Cons 单元串联而成的结构:每个 Cons 单元的 cdr 位,
;;   要么存放着下一个 Cons 单元,要么存放着空列表。
;; atoms:不是 Cons 单元的对象

;; list
(A 2 "A")
()
nil
("A ()")
((A B C))            ; 只有一个元素的列表
;; CAR 与 CDR 这两个名称来源于 Lisp 历史。
;;   最早的 Lisp 运行在 IBM 704 计算机上,该机将字分为地址部分(address)和减量部分(decrement);
;;    CAR 是提取寄存器地址部分内容的指令,CDR 是提取寄存器减量部分内容的指令。

;; 三元素列表 (rose violet buttercup) 等价于 (rose . (violet . (buttercup)))
    --- ---      --- ---      --- ---
   |   |   |--> |   |   |--> |   |   |--> nil
    --- ---      --- ---      --- ---
     |            |            |
     |            |            |
      --> rose     --> violet   --> buttercup

;; 关联列表类型 alist
;; 它的元素都是 cons 单元
(setq alist-of-colors
      '((rose . red) (lily . white) (buttercup . yellow)))
((rose . red) (lily . white) (buttercup . yellow))
;; 这个变量是一个包含三个元素的关联列表。在第一个元素中,rose 是键,red 是值。

;;;; 数组类型
;; 四种数组:strings字符串、vectors向量、bool-vectors布尔向量和 char-tables字符表。
;; 布尔向量只能存放 t 或 nil。
;; 所有 Emacs Lisp 数组都是一维的。

;;;; 字符串类型
;; 字符串的读取语法是一对双引号,中间包含任意数量的字符
"\""
"foo\r"
"foo\^Ibar"
"foo    bar"
"\N{LATIN SMALL LETTER A WITH GRAVE}"
"à"
"\u00e0"
"à"
;; 转义换行符,lisp 在读取字符串时会忽略转义换;转义空格同样会被忽略
"ab\
cd\ e"
"abcde"
;; 字符串中的非 ASCII 字符
"\xe0"
"\340"

;; 字符串中的不可打印字符
"\t, \C-a"
"       , "
"\M-A"
"\301"
;; 字符串中的文本属性
;; #("characters" property-data...) 属性数据由零个或多个元素组成,每三个为一组
#("foo bar" 0 3 (face bold) 3 4 nil 4 7 (face italic))
;; ‘foo bar’ 的字符串,其中:前三个字符拥有 face 属性,值为 bold(粗体);最后三个字符拥有 face 属性,值为 italic(斜体)。(第四个字符没有任何文本属性)。

;;;; 向量类型
[1 "two" (three)]      ; 包含三个元素的向量
;;;; 字符表类型
;; 字符表 = 用字符当下标的数组
;; 打印长这样:#^[...]
;; 用途:给每个字符绑定信息(大小写、语法、显示、分类等)
(setq my-char-table (make-char-table 'foo "默认值")) ; 创建一个空字符表
(aset my-char-table ?a 'letter-a) ; 给字符 'a' 赋值
(aref my-char-table ?a) ; 取 'a' 的值
letter-a

;;;; 布尔向量类型
;; 布尔向量 是一种一维数组,其元素只能是 t(真)或 nil(假)。
;; 打印表示形式与字符串类似,但开头会以 ‘#&’ 后跟长度值
(make-bool-vector 3 t)
(make-bool-vector 3 nil)
ELISP> ?\C-g
7
 (#o7, #x7, ?\C-g)
ELISP> ?\C-@
0
(#o0, #x0, ?\C-@)
;; 布尔向量的长度不是 8 的整数倍,
;;    其打印表示会显示额外的元素,但这些额外元素实际上无任何意义。
(equal #&3"\377" #&3"\007") ; 
t

;;;; 哈希表类型
(make-hash-table)
#s(hash-table)
;;;; 函数类型
(setq f 'list)
list
(funcall f 'x 'y 'z) ; 获取一个函数对象,然后使用原始函数 funcall 和 apply 来调用
(x y z)
(apply '+ 1 2 '(3 4)) ; 其行为与 funcall 基本一致,但最后一项需为一个对象列表
10
;;;; 宏类型
;; 生成另一段 Lisp 表达式
(defmacro inc2 (var1 var2)
    (list 'progn (list 'inc var1) (list 'inc var2)))
inc2
(macroexpand '(inc2 r s))
(progn (inc r) (inc s))
;;;; 原语函数类型
;; 子程序、内置函数,打印时#<xxx>
(symbol-function 'car) ; 获取符号绑定的函数
#<subr car>
(subrp (symbol-function 'car)) ; subrp 是否为原始函数
t
;;;; 闭包类型
;; 是将函数定义转化为函数值时生成的函数对象
;;;; 记录类型
;; 作用创建不属于 Emacs 内置类型的自定义类型对象
;;;; 类型描述符
;; 用于存放类型相关信息的记录。
;;;; 类型说明符
;; 是表示一种类型的表达式。为函数接口提供文档等。
;; 类型说明符可分为基本类型与复合类型。
(and 1 2) ; 只要其中一个生成nil,则返回nil。否则返回最后一个参数值。
2
(and 1 nil)
nil
(and nil 1)
nil
(or 1 2) ; 只要其中一个生成true,则返回true 内容。否则返回最后一个参数值。
1
(or nil 2)
2
(integer -10 10)
;;;; 自动加载类型
autoload
(defun doctor ()xxxx)
;;;; 终结器类型
;; 当返回的终结器对象在垃圾回收后变为不可达时,Emacs 就会调用与该终结器关联的函数。


;;; 编辑类型