Skip to content

Instantly share code, notes, and snippets.

@xuchunyang
Created December 30, 2014 06:22
Show Gist options
  • Save xuchunyang/25377fedc3cfd624a506 to your computer and use it in GitHub Desktop.
Save xuchunyang/25377fedc3cfd624a506 to your computer and use it in GitHub Desktop.
#+Title: Learning notes for Emacs Lisp This is my notes while reading [[info:elisp][GNU Emacs Lisp Reference Manual]]. * Lisp Data Types ** Type 可以重叠 一个 Lisp "object" 可以有多个 "type",因此只会问是否一个 "object" 属不属于哪一个 "type",而不会问一个 "object" 的 "type" 是什么。 ** 原始类型(primitive types) 每个 object 只能从属于一个原始类型。其它类型是由原始类型构造而成。这些原始类型有: - integer - float - cons - symbol - string - vector - hash-table - subr - byte-code function - (plus several special types, such as "buffer") 注意:与很多语言不同的是:Lisp 中的 type 信息是直接存储在 object 中的 (self-typing),所以无需声明(以告诉 compiler 变量的类型)。 ** Printed Representation Printed representation 是指由 prin1 函数作用与 object 产生的结果。 每个 type 的 printed representation 是唯一的。比如,buffer 类型: #+BEGIN_SRC emacs-lisp :output:result (current-buffer) #+END_SRC #+RESULTS: : # 对应的还有 read syntax,是指 Lisp 解释器读入程序的格式。 ** 编程类型(Programming Types) ELisp 中的数据类型可以分成两大类: 1. Lisp programming 都有的 2. 在 editing 环境中特有的 *** 整数类型(Integer Type) 注意两点: - 范围与机器相关,做运算时不检查溢出。 - 过大或过小会自动用 floating-point 数存放 一个例子: -123. 其中符号'-'、'+'和最后的'.'可选。 *** 浮点类型 (Floating-Point Type) 使用 C 中的 double 类型。 用科学计数法表示,一个例子(1500.0的几种写法): - 1500.0 - +15e2 - +15e+2 - 15.0e+2 - .15e4 *** 字符类型(Character Type) **** 字符是整数 比如 'a' 就是其 ASCII 表中的代码 97: #+BEGIN_SRC emacs-lisp :output:result ?a #+END_SRC #+RESULTS: : 97 **** 用字符的code 来表示字符 也可以用字符的代码来表示字符。一共有 3 中方式,参见 [[info:elisp#General%20Escape%20Syntax][info:elisp#General Escape Syntax]]。 对于特殊的字符,还有更多的表示方法: - 控制字符(Ctrl) [[info:elisp#Ctl-Char%20Syntax][info:elisp#Ctl-Char Syntax]] - Meta 字符 [[info:elisp#Meta-Char%20Syntax][info:elisp#Meta-Char Syntax]] *** 符号类型(Symbol Type) 用来表示函数、变量和属性列表,有着唯一的 identity。 Elisp 中的 “一个Symbol” 是指 “一个带有名称(name)的 object”,这个名称(name)即 作为 Printed Representation。 *** 序列类型(Sequence Type) 即有序集合,有两种类型: - lists :: 可放任何类型、长度可变(更多参考下一个部分中的 list Type) - arrays :: 长度固定、进一步可以分成 string、vectors、char-tables 和 bool-vector *** Cons Cell 和 List Types "Cons cell" 是指由 CAR slot 和 CDR slot 构成的 object,其中,每种 slot 都可以保 存任意的 lisp object。而 "list" 就是一系列的 "cons cell" 链接而成的。 "Cons cell" 是 Lisp 中的关键类型,而不属于这一类型的就叫做 "atoms"。 list 的 read syntax(Lisp 解释器读入程序的格式)和 printed representation 是相同 的。 **** Cons cell 的显示写法(Dotted Pair Notation) 或者是一般写法。 (1 2 3) => (1 . (2 . (3 . nil))) 当 CDR 不是 list 时,需要用 Dotted Pair 表示法,比如: (A . B) *** 关联列表类型(Association List Type) "association list" 或者 "alist" 是一种特殊的 list,元素是 Cons cells。每一个元素 的 CAR 最为 key,CDR 作为 accessing value。 比如: #+BEGIN_SRC emacs-lisp (setq alist-of-colors '((rose . red) (lily . white) (buttercup . yellow))) #+END_SRC 变量 alist-of-colors 是一个由3个元素组成的 alist。对于第一个元素,rose 是 key, 而 red 是值。 *** 数组类型 (Array Type) 数组是用来存放其它 object 的,保存在连续的内存块中,访问数组中的任意元素的时间差 不多。Elisp 中定义了 4 中数组: - string - vector - bool-vector :: hold 't' or 'nil' - char-table 数组一经创建,其长度即不可变的。index 从 0 开始。 Elisp 中数组是一维的。 数组类型是序列类型的子集(就像前面提到的一样)。 *** String 类型 String 在 lisp 中是常量。 手册中详细地介绍了: - String 中的 Non-ASCII 的处理 - String 的 text properties *** Vector 类型 vector 是由任意类型构成的一维数组,一个 vector 例子: #+BEGIN_SRC emacs-lisp :output:result [1 "two" (three)] #+END_SRC #+RESULTS: : [1 "two" (three)] 可以看到 printed representation 与 read syntax 相同。 *** Char-Table 类型 *** Bool-Vector 类型 #+BEGIN_SRC emacs-lisp :output:result (make-bool-vector 3 nil) #+END_SRC #+RESULTS: : #&3"" *** Hash Table 类型 #+BEGIN_SRC emacs-lisp :output:result (make-hash-table) #+END_SRC #+RESULTS: : #s(hash-table size 65 test eql rehash-size 1.5 rehash-threshold 0.8 data ()) *** 函数类型(Function Type) 像一般的编程语言一样,Lisp 函数也是可执行代码,只是不同的是,Lisp 函数也是 object。 *** Macro 类型 Lisp Macro 是指由用户定义的 Lisp 扩展,跟函数不同的是充数的传递方式。 不要跟 keyboard macro 搞混了,这两者没有关系。 *** Primitive Function 类型 用 C 写成的函数,从 Lisp 中调用。 #+BEGIN_SRC emacs-lisp :output:result (symbol-function 'car) (subrp (symbol-function 'car)) ; is this primitive function? #+END_SRC #+RESULTS: : t *** Byte-code 类型 编译好了的 lisp 函数。 *** Autoload Type ** 编辑特定的类型(Editing Types) *** Buffer Type 与 buffer 关联着的数据有: - a local syntax table - a local keymap - a list of buffer-local variable bindings - overlays - text properties for the text in the buffer 主要规定了一个 buffer 中 text 的显示格式、key 绑定、buffer 特定的变量。 buffer 没有 read syntax,其 printed representation,比如: #+BEGIN_SRC emacs-lisp :output:result (current-buffer) #+END_SRC #+RESULTS: : # *** Marker Type 表示某个 buffer 中的位置。 同样没有 read syntax, #+BEGIN_SRC emacs-lisp :output:result (point-marker) #+END_SRC #+RESULTS: : # *** Window Type #+BEGIN_SRC emacs-lisp :output:result (selected-window) #+END_SRC #+RESULTS: : # *** Frame Type 还有很多,参考手册 [[info:elisp#Editing%20Types][info:elisp#Editing Types]] ** Read Syntax for Circular Objects 用 '#N=' 和 '#N#" 来表示一个列表中的其它元素。 以下两者是不同的 #+BEGIN_SRC emacs-lisp :output:result '(#1=(a) b #1#) '((a) b (a)) #+END_SRC #+RESULTS: | (a) | b | (a) | 一个 circular 结构(一个 list 中的元素是这个 list) #+BEGIN_SRC emacs-lisp :output:result (prog1 nil (setq x '#1=(a #1#))) (eq x (cadr x)) #+END_SRC #+RESULTS: : t ** 类型检测(Type Predicates) 一系列的检测函数参见:[[info:elisp#Type%20Predicates][info:elisp#Type Predicates]] 一个实例: #+BEGIN_SRC emacs-lisp (defun add-on (x) (cond ((symbolp x) ;; If X is a symbol, put it on LIST. (setq list (cons x list))) ((listp x) ;; If X is a list, add its elements to LIST. (setq list (append x list))) (t ;; We handle only symbols and lists. (error "Invalid argument %s in add-on" x)))) #+END_SRC 最通用的使用 type-of 函数,不过只能对基本类型使用的。 ** 相等检测(Equality Predicates) - eq - equal - equal-including-properties eq > equal:equal 检测两 object 的 components,而 eq 则需要完全相等,更多参考手 册 [[info:elisp#Equality%20Predicates][info:elisp#Equality Predicates]]。 * Numbers 包括了整数(integer)和浮点数(floating-point number)。 整数基础(#+letter+integer,其中 letter 代表进制,也可用 'r' 前面加个 integer 表 示不同的进制): #+BEGIN_SRC emacs-lisp 44 #b101100 #x2c #24r1k #+END_SRC 特殊的浮点数: - infinity - not-a-number ** Number 的类型检测 参考 [[info:elisp#Predicates%20on%20Numbers][info:elisp#Predicates on Numbers]]: - floatp - intergerp - numberp - natnump - zerop ** Number 比较大小 用 '=' 比较数字,不用 eq ,因为 eq 用来判断两个 object 是否相同的,而两个 object 的包含的数字值显然可能相同的。 ** Number 转换 integer => floating-point numbe: float floating-point number => integer: truncate/floor/ceiling/round [[info:elisp#Numeric%20Conversions][info:elisp#Numeric Conversions]] ** 数学计算 (Arithmetic Operations) - 1+ :: plus 1 - 1- :: minus 1 - + - - - * - / - % :: dividend division - mod :: similar with % but some differences 还有常见和不常见的的数学函数。 还有随机数。 * Strings and Characters 定长数组(array),也就也是序列(sequence).其内容不可变。 ** String 的检测 [[info:elisp#Predicates%20for%20Strings][info:elisp#Predicates for Strings]]: - stringp - string-or-null-p - char-or-string-p ** 创建 String - make-string - string - substring - concat - split-string ** Modifying String ** 比较 String - char-equal - string= - string< - sort 更全面的,参考 [[info:elisp#Text%20Comparison][info:elisp#Text Comparison]] 。 ** 转换 String/Char - number-to-string - string-to-number - char-to-string - string-to-char ** 格式化 String - format ** 大小写转换 - downcase - upcase * Lists list 表示由数个(包括0)元素组成的一个序列。这些元素是 cons cell。 ** list 的检测 [[info:elisp#List-related%20Predicates][info:elisp#List-related Predicates]] - consp - atom - listp - nlistp - null ** 访问 list 中的元素 - car cons-cell - cdr cons-cell - car-safe object - pop listname - push listname - nth n list - nthcdr n list - last list &optional n - save-length list ** 构造 Cons cells 和 Lists - cons object1 object2 - list &rest objects #+BEGIN_SRC emacs-lisp :output:result (list 1 2 3) #+END_SRC #+RESULTS: | 1 | 2 | 3 | - make-list length object #+BEGIN_SRC emacs-lisp :output:result (make-list 3 'pigs) #+END_SRC #+RESULTS: | pigs | pigs | pigs | - append &rest sequence - number-sequence from &optional to separation ** 改变 List - push element listname - add-to-list symbol element &optional append compare-fn - add-to-ordered-list symbol element &optional order ** 改变 List 的结构 - setcar - setcdr ** alist 关联列表, - assoc key alist - rassoc value alist - assq key alist - rassq value alist - assoc-default - copy-alist alist ** Property Lists 'plist' * Sequences, Arrays, and Vectors #+BEGIN_SRC _____________________________________________ | | | Sequence | | ______ ________________________________ | | | | | | | | | List | | Array | | | | | | ________ ________ | | | |______| | | | | | | | | | | Vector | | String | | | | | |________| |________| | | | | ____________ _____________ | | | | | | | | | | | | | Char-table | | Bool-vector | | | | | |____________| |_____________| | | | |________________________________| | |_____________________________________________| #+END_SRC * Hash Tables a very fast kind of lookup table * Symbols * Evaluation ** Self-Evaluating Forms #+BEGIN_SRC emacs-lisp '123 123 (eval '123) (eval (list 'message "hello")) #+END_SRC #+RESULTS: : hello ** Symbol Forms ** 如何区别 list forms 判断一个非空 list 是: - function call - macro call - special from 通过看第一个元素。 ** symbol function indirection ** Evaluation of Function Form ** Evaluation of Macro Form ** Special Forms - and - catch - cond - condition-case - defconst - defvar - function - if - interactive - lambda - let, let* - or - prog1, prog2, progn - quote - save-current-buffer - save-excursion - save-restriction - setq - setq-default - while ** Autoloading The "autoload" feature allows you to call a function or macro whose function definition has not yet been loaded into Emacs. ** Quote (') (quote object) 直接返回 object,不执行。对于 self-evaluating 的 object 无需 quote。 ** Backquote (`)与(,)和(,@) 与 quote 相似,但是可以用 "," 选择性执行部分。 #+BEGIN_SRC emacs-lisp `(a list of (+ 2 3) element) '(a list of (+ 2 3) element) `(a list of ,(+ 2 3) element) ;; 这里执行(+ 2 3) `(1 2 (3 ,(+ 4 5))) #+END_SRC #+RESULTS: | 1 | 2 | (3 9) | ** Eval 显式执行 * 控制结构 ** 顺序执行 - progn - prog1 :: same as progn, but return the first expression - prog2 :: like prog1, but return the second expression ** 条件执行(if/cond/when/unless) *** if 及其变种 when/unless when 和 unless 是 if 的简便写法。 #+BEGIN_SRC emacs-lisp (if nil (print 'ture) 'very-flase) (when CONDITION A B C) ;; same as => (if CONDITION (progn A B C) nil) (unless CONDITION A B C) ;; same as => (if CONDITION nil A B C) #+END_SRC *** cond and pcase 任何 cond 表达式都能用 if 实现: #+BEGIN_SRC emacs-lisp (setq a 5) (cond ((eq a 'hack) 'foo) (t "default")) (if A B C) ;; => (cond (A B) (t C)) #+END_SRC pcase (Pattern matching case statment) #+BEGIN_SRC emacs-lisp (pcase (get-return-code x) (`success (message "Done!")) (`would-block (message "Sorry, can't do it now")) (`read-only (message "The shmliblick is read-only")) (`access-denied (message "You do not have the needed rights")) (code (message "Unknown return code %S" code))) #+END_SRC *** not / and / or *** Iteration (while / dolist / dotimes) *** Nonlocal Exits (catch error) * 变量(Variables) ** 全局变量(Global Variables) ** 基础常量 (t, nil) [[info:elisp#Constant%20Variables][info:elisp#Constant Variables]] ** 局部变量 用 let / let* * 函数(Functions) * Macros - defmacro - macroexpand #+BEGIN_SRC emacs-lisp (defmacro inc (var) (list 'setq var (list '1+ var))) (defmacro inc2 (var1 var2) (list 'progn (list 'inc var1) (list 'inc var2))) #+END_SRC
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment