EmacsでのCommon Lisp開発

Posted on August 10, 2020 by nobiruwa

tl;dr

$ sudo apt-get -y install git build-essential automake libcurl4-openssl-dev
$ git clone -b release https://github.com/roswell/roswell.git $HOME/repo/roswell.git
$ cd $HOME/repo/roswell.git
$ sh bootstrap
$ ./configure --prefix=$HOME/opt/roswell
$ make
$ make install

// $HOME/opt/roswell/binをPATHに通した後:
$ ros setup

動機

QuickLispを使っていたのですが、cronで動作するスクリプトを作成するためにQuickLispのディレクトリをスクリプト内に埋め込んだり、イマイチ使いこなせている気がしなかったので、環境を管理するユーティリティがないかを探してRoswellに辿り着きました。

RoswellはCommon Lispの実装のインストーラー兼マネージャー兼ランチャー兼etc.です。

丁寧なWikiがあり、使い方を学ぶことができます。

インストール

Wikiで十分に説明されています。が、私はユーザーディレクトリのoptディレクトリにインストールしてPATHを通すスタイルが好きなので、実行するコマンドを少し変更しました。ソースコードリポジトリのローカルディレクトリ名も<プロジェクト名>.<コマンド名>(ex: roswell.gitrxvt-unicode.svnなど)と独特の管理をしています。

$ sudo apt-get -y install git build-essential automake libcurl4-openssl-dev
$ git clone -b release https://github.com/roswell/roswell.git $HOME/repo/roswell.git
$ cd $HOME/repo/roswell.git
$ sh bootstrap
$ ./configure --prefix=$HOME/opt/roswell
$ make
$ make install

// $HOME/opt/roswell/binをPATHに通した後:
$ ros setup

Emacsのセットアップ

Wikiのfor Emacsの通りです。

$ ros install slime

私はddskkを使って日本語入力をしており、SKKの変換ができるようキーバインドを変更しています。

(let ((slime-helper (expand-file-name "~/.roswell/helper.el")))
  (when (file-exists-p slime-helper)
    (load slime-helper)

    ;; SLIMEとSKKとの衝突を回避する設定
    ;; 特定の場面で、SLIMEとSKKとの間でスペースキーのキーバインドが競合して、SKKでの変換ができなくなります。
    ;; https://lisphub.jp/common-lisp/cookbook/index.cgi?SLIME#H-33uy3rfpe0845
    (defun my-slime-space (n)
      (interactive "p")
      (if (and (boundp 'skk-henkan-mode) skk-henkan-mode)
          (skk-insert n)
        (slime-autodoc-space n)))
    (define-key slime-autodoc-mode-map " " 'my-slime-space)
    (setq inferior-lisp-program "ros -Q run")))

サンプルスクリプト

WikiのScripting with Roswellの通りです。

$ cd $HOME
$ ln -s .roswell/local-projects lispprojects
$ cd lispprojects
$ mkdir scripting-with-roswell
$ cd scripting-with-roswell
$ ros init fact

// fact.rosが生成されるので、次のように編集する:
$ cat fact.ros
#!/bin/sh
#|-*- mode:lisp -*-|#
#|
exec ros -Q -- $0 "$@"
|#

(defun fact (n)
  (if (zerop n)
      1
      (* n (fact (1- n)))))

(defun main (n &rest argv)
  (declare (ignore argv))
  (format t "~&Factorial ~D = ~D~%" n (fact (parse-integer n))))
$ ./fact.ros 10
Factorial 10 = 3628800