位元詩人 [Common Lisp] 程式設計教學:使用 Emacs 搭配 SLIME 寫 Common Lisp 程式

Facebook Twitter LinkedIn LINE Skype EverNote GMail Yahoo Email

前言

SLIME 本身是 Emacs 的模式 (mode),其目的是輔助撰寫 Common Lisp 程式。

雖然現在使用 Emacs 的程式設計者逐漸變少,SLIME 在 Common Lisp 開發工具中算是整合得不錯的。許多 Common Lisp 的教學資源還是會提到 SLIME,所以筆者特地寫了一篇文章來介紹這個開發工具。

如果讀者不需要 REPL 環境,不一定要用 SLIME,也可以用 VSCode 等編譯器來寫 Common Lisp 程式。當我們用 VSCode 寫 Common Lisp 程式時,把 Common Lisp 當成 Python 或 Ruby 等直譯語言來用,不注重 REPL 環境。

為什麼不用 Emacs

如果讀者在學 Common Lisp 前完全沒用過 Emacs,最好慎重考慮要不要入這個坑。Emacs 有幾個顯而易見的缺點:

  • 熱鍵多到爆炸
  • 設定檔不易撰寫
  • 誤以為 Emacs 是 IDE
  • 遠端主機幾乎不會預裝 Emacs

因為 Emacs (註) 本身其實是一個大型的 Lisp 程式,該編輯器使用了自己的 Lisp 方言,即 Emacs Lisp。除了底層用 C 來實作以外,其他的部分都是以 Emacs Lisp 來實作。所以,當我們在寫 Emacs 設定檔時,就是在寫 Emacs Lisp 程式。

(註) 指 GNU Emacs。

很多 Emacs 學習資源會讓 Emacs 初學者以為 Emacs 是萬能的,浪費許多時間來調校,結果只是重造其他編輯器或 IDE 的輪子。其實 Emacs 本質上仍然是一個編輯器,如果需要一些和寫程式相關的功能,還是針對各個語言找專門的 IDE 比較好。

此外,由於 Emacs 比較肥大,遠端主機通常不會預裝 Emacs。如果想要學習可在命令列環境使用的編輯器,還是去學 Vim 或 nano(1) 比較實在。

為什麼使用 Emacs

雖然筆者嘴了一下 Emacs 的缺點,但對學習 Common Lisp 來說,Emacs 仍然是值得考慮的工具。因為:

  • SLIME 整合得很好
  • 學會 Common Lisp 自然會設置 Emacs

雖然 Common Lisp 和 Emacs Lisp 是不相容的,但學習了其中一種 Lisp 方言後,要轉換到另一個 Lisp 方言不會太困難。用 Emacs 學 Common Lisp 可說是相輔相成。

如果讀者懶得自己調校 Emacs,可以考慮使用 Portacle。該軟體整合了以下軟體:

  • Emacs
  • SBCL (Steel Bank Common Lisp)
  • SLIME
  • Company:自動補完
  • QuickLisp:套件管理軟體
  • Git:知名的版本控制軟體

本文仍會自行設置 SLIME。對 Portacle 有興趣的讀者可以自己玩玩看。

使用 SLIME 的前置知識

Emacs 是需要花一點時間學習才能使用的軟體,但本文的篇幅不足以介紹 Emacs 的使用方式。如果想要學一下 Emacs 的用法,可以參考 Emacs 101

雖然寫 Emacs 101 的大大已經跳槽到 VSCode 了,這件事無損讀者學習 Emacs。

Emacs 設定檔

通常是 $HOME/.emacs$HOME/.emacs.d/init.el 。在使用 Emacs 的過程中,自然會在 $HOME/.emacs.d 安裝一些套件,所以建議使用後者為設定檔。

Windows 系統中等效家目錄的位置是 %USERPROFILE% 變數所在的位置。假定使用者為 user ,家目錄即位於 C:\Users\user 。舊版的 Windows 系統的家目錄會有空格,最好另行將沒有空白、有讀寫權限的目錄設置至 HOME 變數。

安裝 SLIME

使用 MELPA 安裝 SLIME

新版的 Emacs 已經內建 MELPA 了,所以就不用自己安裝套件管理程式,但還是要自己設置一下。在 Emacs 設定檔中加入以下設定:

; Emacs Lisp
(require 'package)
(package-initialize)
(add-to-list 'package-archives
             '("melpa" . "https://melpa.org/packages/") t)
(add-to-list 'package-archives
             '("melpa-stable" . "http://stable.melpa.org/packages/") t)

M-x package-refresh-contents 指令來更新套件清單。

然後再用 M-x package-install RET M-x slime 指令來安裝 SLIME。

根據自己使用的 Common Lisp 實作品來指定路徑。以下範例設置是以 64 位元 Windows 的 Clozure CL 為準:

; Emacs Lisp
(setq inferior-lisp-program "C:/Users/user/Documents/ccl/wx86cl64.exe")

如果讀者使用不同系統或不同 Common Lisp 實作品,請自行修改路經。

手動安裝 SLIME

手動安裝 SLIME 的方式其實不會太麻煩,用 Git 將 SLIME 的 repo 拷貝 (clone) 下來後,在 Emacs 設定檔中指定 SLIME 的路經即可。參考以下設置:

; Emacs Lisp
(add-to-list 'load-path "C:/Users/user/Documents/slime")
(require 'slime-autoloads)
(setq inferior-lisp-program "C:/Users/user/Documents/ccl/wx86cl64.exe")

請不要將此範例設置直接複製貼上,而要根據自己系統實際的情形來修改。

第一次使用 SLIME

使用以下指令來啟動 Emacs 並開啟 source.lisp

$ emacs source.lisp

source.lisp 不存在,會自動建立一個同名的空白檔案。所以,不論 source.lisp 是否存在,該行指令皆可順利執行。

在預設情境下,Emacs 會以圖形介面模式開啟。但 Emacs 原本的設計是在命令列環境下操作。若想在命令列模式中使用 Emacs,可加入 -nw 參數:

$ emacs -nw source.lisp

這時候,不論 Emacs 是否有圖形介面,皆會以命令列模式來開啟。

進入編輯畫面後,輸入 M-x slime 來啟動 REPL 環境。為什麼不在開啟 Lisp 檔案時自動啟動 REPL 環境呢?因為同一個軟體專案很有可能有多個 Lisp 原始碼,每開一個 Lisp 原始碼就觸發一次 REPL 環境反而是不良的行為。

開啟 REPL 環境後,Emacs 會分割成上下兩個緩衝區 (buffer):

使用 Emacs 的 SLIME 模式

註:筆者在 macOS 中以命令列模式執行 Emacs,使用 SLIME 模式編輯 Common Lisp 程式。

使用 C-x o 指令即可在多個緩衝區間切換。透過 SLIME 的整合,我們可以在 Emacs 內同時使用編輯器和 REPL 環境。

編輯完成後,記得用 C-x C-s 存檔。

使用 C-c C-k 指令即可在不離開 Emacs 的前提下編譯並執行 Lisp 程式碼。

查詢符號 (Symbol) 和函式 (Function) 的用法

除了編譯和執行程式外,SLIME 支援即時 API 查詢。將游標移到特定的符號或函式後,使用 C-c C-d h 指令即可自動連線到 HyperSpec 中相對應的頁面。算是相當方便的功能。

使用 SLIME 的注意事項

SLIME 將 Common Lisp 當成後端 (backend) 程式來使用。在 Common Lisp 中使用 quit 指令會導致 SLIME 和 Common Lisp 間的連線中斷。所以,在使用 SLIME 時,要停掉 quit 指令。

參考以下短例:

;; Custom-made main function.
(defun main ()
  (write-line "Hello World")
  ;; Disable `quit` command in SLIME session.
  #-swank (quit)
  )

SLIME 利用 swank 伺服程式和 Common Lisp 後端連線。所以,此範例程式在 swank session 中選擇性註解掉 quit 指令。程式就不會從 SLIME 的 REPL 環境中斷掉。

關於作者

身為資訊領域碩士,位元詩人 (ByteBard) 認為開發應用程式的目的是為社會帶來價值。如果在這個過程中該軟體能成為永續經營的項目,那就是開發者和使用者雙贏的局面。

位元詩人喜歡用開源技術來解決各式各樣的問題,但必要時對專有技術也不排斥。閒暇之餘,位元詩人將所學寫成文章,放在這個網站上和大家分享。