上一篇:讓 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 列表中目錄搜索給定名字的文件並載入,除此之外,它也沒有更多用途了。
cons,car 以及 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 首元素之後的元素構成的列表,亦即 car 和 cdr 可讓一個列表身首異處。至於 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 世界的自主之地。