上一篇让 Emacs 略带感性

Emacs 用了一段时间后,只要你一时没忍住,安装了几个插件,就会发现 init.el 文件实属兵家必争之地。

你亲力亲为所作的那部分配置,与一堆陌生的配置混在一起,一旦出现某些冲突,通常很难快速确定问题出在何处。我们有必要对 init.el 中的配置尽力予以隔离。至少,我们真正清楚的那部分配置,可隔离出来,单独存放于一份 .el 文件中,然后在 init.el 文件里将其载入。一方面可以控制 init.el 的复杂度,另一方面也便于问题排查。

Emacs 提供了一个列表类型的全局变量 load-path。假设我们将自己清楚的那部分配置代码从 init.el 中移除,将其单独存放在 ~/.my-emacs 目录里的 my-config.el 文件,然后只需将该目录添加到 load-path,之后便可在 init.el 里用 load 载入 my-config.el 文件了。

现在,为 init.el 添加以下代码

(setq load-path (cons "~/.my-emacs" load-path))
(load "my-config.el")

之后每次打开 Emacs,它都会自动从 ~/.my-emacs 加载 my-config.el 文件,从而使得我们的配置代码生效。

上述代码所用的 cons,我在讲述关联列表时提起过它一次,当时是用它构造键值对,实际上,它也能用于构造列表。至于 load,只需知道它能从 load-path 列表中目录搜索给定名字的文件并载入,除此之外,它也没有更多用途了。

conscar 以及 cdr 是所有 Lisp 语言最为基础的函数。在早期的 Lisp 机上,它们甚至是 CPU 可直接执行的指令。我们之所以一直没有像那些 Lisp 教科书,从一开始就介绍它们的作用和意义,原因是 Emacs 已经基于它们实现了许多高级功能,以至于我们几乎不需要使用它们,就已经能够编写许多有用的程序了,但作为 Lisp 语言之根本,不掌握它们,近乎数典忘祖。

首先回顾一下,这三个基础函数在键值对或二元组方面的用法:

(let ((x (cons 1 2)))  ;; x 为 (1 . 2)
  (car x)  ;; 结果为 1
  (cdr x))  ;; 结果为 2

现在,用 cons 构造列表,例如

(cons 1 nil)

(cons 1 '())

上述两个表达式是等效的,它们的求值结果都是 (1) 即只含有单个元素的列表,且元素为 1。另外,你应当明白了,在 Elisp 语言里,nil'(),反之亦然。'() 即空列表,故而 nil 也是空列表,你可以试着对以下表达式求值,以确认这个事实。

(equal nil '())

equal 是 Elisp 语言里最为通用的相等测试函数,它不仅要比较两个值是否相等,也要比较它们的类型是否相同。上述表达式求值结果为 t,足以证明 nil'()

再看以下示例:

(let ((x (cons 1 nil)))
  (car x)  ;; 结果为 1
  (cdr x)) ;; 结果为 nil

再看以下示例:

(let ((x (cons 1 nil)))
  (setq x (cons 0 x)) ;; 结果为 (0 1)
  (car x)  ;; 结果为 0
  (cdr x)) ;; 结果为 (1)

你会发现,上述代码中的 cdr 表达式的求值结果是一个列表。现在,你应该能认识到,若 x 是一个列表,则 (car x) 可以获取 x 的首元素,而 (cdr x) 获取的是 x 首元素之后的元素构成的列表,亦即 carcdr 可让一个列表身首异处。至于 cons,它用于向列表首部追加一个元素,所以现在你应该清楚以下代码的含义了!

(setq load-path (cons "~/.my-emacs" load-path))

函数 length,之前我们曾用它获取过字符串的长度。实际上,它也可以用于获取列表长度。例如

(length load-path)

在我的机器上,求值结果为 36,表示 load-path 已记录了 36 个目录。倘若你想查看它们,可以用 dolist 遍历它,并逐一输出目录的路径:

(dolist (dir load-path)
  (message "%s" dir))

练习:编写一个递归函数 reverse-list,让它可将列表 (0 1 2 3 4 5) 逆转,结果为 (5 4 3 2 1 0),然后将其定义修改为 while 表达式的形式。

Emacs 提供了 push 函数,它可以简化上述赋值表达式。例如

(push "~/.my-emacs" load-path)

以后,倘若我说,向 init.el 里添加某些代码时,你可以酌情考虑,是否应该将其加入你的 my-config.el 文件。我的建议是,my-config.el 永远只存放你真正熟悉的那部分代码,你甚至对其中每一行代码都了如指掌,它们构成了你在 Emacs 世界的自主之地。


garfileo
6k 声望1.9k 粉丝

这里可能不会再更新了。