Emacs lisp 基础

使用 Emacs 大概也有大半年了,越用越觉得它的强大,始终都有惊喜,每次看到一个功能,心中想:Emacs 可以吗?答案真的往往会是 Yes!

1
2
3
4
(defun factorial (n)
(if (<= n 1)
1
(* n (factorial (- n 1)))))

上面这种充满括号的奇怪的语言叫 Lisp,它是仅次于 Fortran 的最老的高级程序设计语言,名称来源于 LISt Processing,它有两个方言,分别是 Common Lisp 和 Scheme。 Emacs lisp (elisp) 来源于 Common Lisp。使用 Emacs,如果不能自己打造适合自己的功能,虽然仍然可以享受 Emacs 带来的流畅和便利,但却会与另一种乐趣失之交臂,这篇文章简要叙述 elisp 的基本概念和语法。

Hello World

1
(message "Hello, World!")

使用 C-x C-e 执行,便可以从 minibuffer 中看到这段代码的输出,简单吧?

变量

1
2
(set 'numstr 'nine)
(setq numstr 'nine)

set 和 setq 用来对变量赋值,变量不需要事先声明,而且都是全局的。

在 C 中,int x = 3; 表示将 3 赋值给 x,我们不能直接再使用 x 这个 symbol,因为它已经代表了整型 3 或者代表之后重新赋的新值,如果需要使用 x,那就只能重新定义 char c = ‘x’,而在 elisp 中,我们针对的就是 symbol,也就是说可以同时使用 x 和 x 所代表的值。比如上面代码,set 语句中 number 和 nine 前面都有一个 ' (quote) 符号,这个符号到底做什么用呢?

它告诉 Lisp 解释器不要去执行这个 symbol,而是直接使用。比如在 L1 执行完后,numstr 代表的是 nine,而 'numstr 仍然指的是 numstr. 为了书写方便,setq 免去了 ',作用同 set

1
2
3
(let ((name 'Chris)
(age '26))
(message "Name is %s, %d years old" name age))

let 用来定义在特定区域中的局部变量,还有两一种形式,如下

1
2
3
4
(let (name age)
(setq name 'Chris)
(setq age '26)
(message "Name is %s, %d years old" name age))

运算

1
2
3
4
5
6
7
8
(+ 1 2)        ; = 3
(+ 1 2 3) ; = 6
(- 8 5) ; = 3
(* 2 3) ; = 6
(/ 7 2) ; = 3
(/ 7 2.0) ; = 3.5
(% 9 4) ; = 1
(expt 2 3) ; = 8

这里需要强调的是如果需要输入浮点数时,需要在数字后面加 .0,否则还是会被当整型处理的。如 L5 & L6。

比较

在 elisp 中,false 用 nil 来表示,空列表也用 nil 来表示,其余的都是 true,也就是说 0 和 空字符串也是 true。

1
2
3
4
5
6
7
8
9
10
(< 2 3)                 ; = t
(> 2 3) ; = nil
(<= 2 2) ; = t
(>= 2 3) ; = nil
(= 2 3) ; = nil
(string= "he" "he") ; = t
(string< "he" "ie") ; = t
(not (< 3 2)) ; = t
(or (< 3 2) (< 2 3)) ; = t
(and (< 3 2) (< 2 3)) ; = nil

string< 比较的是字符串的字典顺序,没有 string>。

表达式

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
(if (< 3 2)
(message "3 < 2")
(message "3 > 2"))

(when (< 2 3)
(setq x 2)
(setq y 3)
(message "%d < %d" x y))

(setq x 0)
(while (< x 4)
(print "hit ")
(setq x (1+ x)))

(progn
(setq x 2)
(setq y 3)
(setq z (+ x y)))

条件判断 if,t 则执行下一句 L2,nil 则执行第三句 L3,when 表示如符合条件,就执行所有语句,while 为循环语句,L10 打印出 4 个 hit,progn 表示一个代码块,返回最后一个语句的返回值。

1
2
3
4
5
6
(setq x 9)
(cond
((<= x 0) 0)
((= x 1) 1)
((> x 1)
(+ x 1)))

cond 用来列出一系列条件,以及满足该条件时的动作,上面代码表示当 x<=0 时,返回 0,当 x=1 时返回 1,当 x>1 时,返回 x+1 的值。

函数

1
2
3
(defun show (type)
(message "This is a my first %s function" type))
(show 'demo)

如果想要在 Emacs 中使用 M-x 调用的话,需要加 (interactive)

1
2
3
(defun yeah ()
(interactive)
(message "yeah!"))

interactive 可以带很多参数,具体请参考

lambda 用来定义匿名函数

1
((lambda (number) (* 7 number)) 3)

在函数定义后加参数就可以调用该匿名函数了。