Lispy Days

趣味で Lisp な日々 (index) (weblog) (view) (edit) (help)

Common Lisp の開発環境

Emacs 標準の S 式編集コマンド

こんなコードがあったとする.

S 式用の,Emacs の標準機能を以下に示す.

(*移動*)
ESC C-a : beginning-of-defun : defun の先頭へ移動
ESC C-e : end-of-defun : defun の末尾へ移動
ESC C-f : forward-sexp : カーソル位置から始まる S 式の末尾に移動
ESC C-b : backward-sexp : カーソル位置より一つ後の S 式の先頭に移動
ESC C-d : down-list : 1 レベル内側の S 式へ移動
ESC C-u : backward-up-list : 1 レベル外側の S 式へ移動
ESC C-n    : forward-list : 括弧のグループを超えて前方へ移動
ESC C-p    : backward-list : 括弧のグループを超えて後方移動
ESC C-k : kill-sexp : カーソル位置から始まる S 式を kill する
ESC C-backspace : backward-kill-sexp : カーソル位置より一つ後の S 式を kill する
(*インデント*)
割り当て無し : indent-sexp : S 式内を indent する
(*マーク*)
ESC C-SPC : mark-sexp : 引数の数だけ S 式をマークする
ESC C-h : mark-defun : defun 全体をマークする
(*編集*)
ESC C-t : transpose-sexps : ポイント位置前後の S 式を入れ換える
C-x n d : narrow-to-defun : defun の範囲に narrow する
C-x n w    : widen : narrow-to-defun を解除

SLIME

SLIME の公式ページ から入手可能.いろいろと面白い機能がある.メインの環境が CMUCL な こともあって,最近は ILISP から SLIME に乗りかえ気味.現在は CMUCL, SBCL, OpenMCL, AllegroCL, LispWorks, CLISP といった処理系に対応.

SLIME のセットアップ

README によれば,ダウンロードした slime を展開したら,

(add-to-list 'load-path "/the/path/to/this/directory")
(require 'slime)
(add-hook 'lisp-mode-hook (lambda ()
                            (slime-mode t)
                            (show-paren-mode)))

とするだけ.Common Lisp らしいインデントにするには↓をどーぞ.(私の趣味ですが)

(add-hook 'slime-mode-hook
      (lambda ()
        (setq lisp-indent-function 'common-lisp-indent-function)))

;; Additional definitions by Pierpaolo Bernardi.
(defun cl-indent (sym indent)
  (put sym 'common-lisp-indent-function
       (if (symbolp indent)
       (get indent 'common-lisp-indent-function)
     indent)))

(cl-indent 'if '1)
(cl-indent 'generic-flet 'flet)
(cl-indent 'generic-labels 'labels)
(cl-indent 'with-accessors 'multiple-value-bind)
(cl-indent 'with-added-methods '((1 4 ((&whole 1))) (2 &body)))
(cl-indent 'with-condition-restarts '((1 4 ((&whole 1))) (2 &body)))
(cl-indent 'with-simple-restart '((1 4 ((&whole 1))) (2 &body)))

SLIME Features

http://www.cliki.net/SLIME%20Features を勝手に超意訳.思ったより長いから別ページにしようかなぁ….

SLIME の特徴.次のスクリーンショットは見た目はこんなかんじ.

助け合いの精神によって、だれでも以下の文章を修正したり追加したりできます。 (訳注:Web 版では Wiki じゃないのでできません…メールで連絡ください) 変更点 が少なくなったら texinfo にまとめられるでしょう。

Read-Eval-Print-Loop (REPL)

SLIME の Read-Eval-Print ループは Emacs が Lisp への接続を確立するとすぐに *slime-repl* バッファ上に表示されます。REPL バッファは伝統的な *inferior-lisp* バッファに似ていますが、Emacs と Lisp がより統合されています。 トップレベルの一部分は Emacs Lisp で書かれており、Emacs は常にどこにプロンプ トを表示するかを知っており、出力や戻り値の違いを示す事ができます。また、REPL はエラーが発生すると自動的に SLIME のデバッガを使用します。

スクリーンショットの右上が REPL です(その下はデバッガ)。プロンプト、入力、出 力、式の戻り値のそれぞれに別個の色が使われています。

*slime-repl* バッファでは slime-mode キーバーインディングのほとんどが利用可 能です。さらに以下のコマンドが利用できます。

Debugger

SLIME は独自の Emacs に統合されたデバッガを備えています.Lisp は常に Emacs へのリクエストを評価しており,*DEBUGGER-HOOK* はエラー時に使用されるデバッガ にバインドされています.デバッガが起動されると Emacs バッファに利用可能なリ スタートやバックトレースの一部が表示されたエラー画面がポップアップされます. スクリーンショットの右上の上部がデバッガです.

最初はバックトレースの一行だけが表示されています.より多くのフレームを表示す るにはカーソルを下に移動してバッファの最後の --more-- の行に合わせるだけです.

デバッガはリスタートされるまでアクティブなままです.デバッガ内では通常の SLIME コマンドが利用可能で,それらのコマンドのエラーは再帰的にデバッガを呼ぶ 事になります.

リスタートのためのコマンド:

カーソルで指定されたフレームを操作するコマンド:

フレーム間の移動:

Edit Definition

多くの Lisp は関数のソースコードの位置を記録しています.SLIME はこの情報を使って特定のシンボルの定義を見つけます.ユーザーはこの機能のために独立した "タグテーブル" を維持する必要がありません.

SLIME は関数定義にジャンプする前に現在位置をスタックにプッシュします.M-, はこのスタックのトップエレメントをポップし,保存されいていた位置にジャンプします.

お使いの Lisp 処理系のソースコードをインストールする事をお勧めします.ソースを読む事で多くのトリックを学ぶ事ができるからです.CMUCL の場合,次のようにどこにソースコードをインストールしたのかを .cmucl-init.lisp で設定する必要があります.

  (setf (search-list "target:") '("/opt/cmucl/src/"))

SBCL ならば次のように対応する論理パスの定義を行なうと良いでしょう.

  (setf (logical-pathname-translations "SYS") 
        '(("SYS:SRC;**;*.*.*" #P"/opt/sbcl/src/**/*.*")
          ("SYS:CONTRIB;**;*.*.*" #P"/opt/sbcl/contrib/**/*.*")))

Documentation

SLIME は ILISP と同様に Erick Naggum 氏の作成した Common Lisp HyperSpec アク セスのためのパッケージを備えています.それはオンラインバージョンの HyperSpec を使うようになっていますが,もし何らかの理由で HyperSpec をローカルにダウン ロードして使いたい場合には .emacs で

(setq common-lisp-hyperspec-root "file:/usr/local/lisp/CLHS6/HyperSpec/")

のように HyperSpec へのパスを設定してください.

Emacs に組込む web ブラウザは好みがあるので,もし他のブラウザを使いたければ emacs のカスタマイズ設定で "Browse Url Browser Function" から好きなブラウザ を指定してください.

Compilation

SLIME はファイル,定義,バッファ,リージョン,システム(訳注:おそらく defsystem で定義されるやつ)をコンパイルするためのコマンドを備えています.ファ イルをコンパイルするとシステムはコンパイルされたコードを fasl ファイルとして ディスクに保存します.定義やバッファやリージョンをコンパイルするとコードはメ モリ上に記憶され,ファイルには書き出されません.

C-c C-c
  現在のトップレベルフォームをコンパイル
M-x slime-compile-region
  リージョンをコンパイル
C-c C-k
  カレントバッファのファイルをコンパイルし,ロードする(コンパイルが成功した場合だけロードされる)
C-c M-k
  カレントバッファのファイルをコンパイルする(ロードしない)
C-c C-l
  バッファのファイルをロードする
M-x slime-load-sysmtem
  入力されたシステムの変更されたファイルをコンパイルしてロードする

Compiler Warnings Commands

SLIME はコンパイラによって生成された警告を集め,ソース上の適切な位置を見つけ たりコンパイラのメッセージを表示するコマンドを提供します.SLIME は警告に対応 するソースコードにカーソルが重なると表示される注釈を付けます.カーソルに対応 するメッセージはミニバッファ上に表示されます.

M-n
  次のコンパイラの警告位置に移動し,警告を表示します
M-p
  前のコンパイラの警告位置に移動し,警告を表示します
M-x slime-list-compiler-notes
  別のバッファに全てのコンパイラの警告を表示します.
  警告をクリックもしくは RET キーで対応するソースコードをハイライトします

Evaluation

評価コマンドはプログラムの小さな部分をテストするのに便利です.

C-c :
  ミニバッファで式を一つ読み込んで評価し,その値をエコー領域に表示します
  (slime-interactive-eval)
C-x C-e
  ポイント位置の前にある式を評価し,値をエコー領域に表示します
  (slime-eval-last-sexp')
C-M-x
  ポイント位置の後もしくはポイント位置を含むトップレベルフォームを評価し,
  値エコー領域に表示します (slime-eval-defun)
C-x C-p
  ポイント位置の前にある式を評価し,新しい表示バッファに値を pretty-print します
  (slime-pprint-eval-last-expression)
M-x slime-eval-region
  リージョン内の全ての式を評価します
M-x slime-eval-buffer
  バッファ内の全ての式を評価します
C-x M-e
  ポイント位置の前にある式を評価し,値をエコー領域と出力バッファに表示します
  (slime-eval-last-expression-display-output).
C-c C-u
  ポイント位置のシンボルへの関数定義を取り除きます
  (slime-undefine-function).

C-c : はインタラクティブに式を評価するためのもっとも基本的なコマンドです. Emacs はミニバッファから文字列として式を読み込み,それを slime-buffer-package の値とともに Lisp に送ります.Lisp は文字列もパッケージ 内で read し,フォームを評価して文字列として結果を Emacs に返し,Emacs はエ コー領域に結果を表示します.

slime-buffer-package はバッファローカルな変数で,もっとも近い in-package フォー ムから見つけた名前を含みます.もしバッファに in-package フォームが無ければカ レントパッケージ(*package*)の値を使用します.

C-x C-e や C-M-x コマンドは C-c : に似ていますが,ミニバッファから式を読みません.C-x C-e はポイントの前にある S 式を,C-M-x はポイントの後もしくはポイントを含むトップレベルフォームを使用します.トップレベルフォームは最初のカラムが開き括弧から始まる S 式です.

Defvar Hack: C-M-x は defvar から始まるフォームを特別扱いします.もし既にそ の変数が存在しているなら,変数がリセットされます.したがって C-M-x は defvar を defparameter にします.C-x C-e はこのような defvar の特別扱いをしません.

Tip: slime-complete-symbol はポイントの周辺のシンボルを補完に使用する事ができます.それは Lisp バッファでは M-TAB に,ミニバッファでは TAB にバインドされています.

Inspector

slime-mode keybindings overview

ここでは C-h m (describe-mode) で示される slime-mode のキーバインドの要約を 示します.これらのコマンドのサブセットは *slime-repl* バッファでも利用可能で す.

SLIME: The Superior Lisp Interaction Mode for Emacs (minor-mode).


カレントバッファのソースファイルをコンパイルしコンパイラの注意や警告をハイライトするには:
 C-c C-k - カレントバッファのファイルをコンパイルしてロードする
 C-c M-k - カレントバッファのファイルをコンパイルする
 C-c C-c - ポイント位置のトップレベルフォームをコンパイルする

コンパイラの注意を巡回するには:
 M-n - 次の注意へ移動
 M-p - 前の注意へ移動
 C-c M-c - バッファ内の compiler-note を削除

定義を見つけるには:
 M-. - ポイント位置の関数定義を編集する
 M-, - 関数定義の編集から戻る

プログラミング支援
 C-c TAB - ポイント位置の Lisp シンボルの補完( M-TAB と同じ)
 C-c RET - Macroexpand once.
 C-c M-m - Macroexpand all.

クロスリファレンス(CMUCL のマニュアルを参照):
 C-c C-w c - WHO-CALLS a function.
 C-c C-w r - WHO-REFERENCES a global variable.
 C-c C-w s - WHO-SETS a global variable.
 C-c C-w b - WHO-BINDS a global variable.
 C-c C-w m - WHO-MACROEXPANDS a macro.
 C-M-. - Goto the next reference source location. (Also C-c C-SPC)

ドキュメント関連コマンド:
 C-c C-d - シンボルを Describe
 C-c C-a - Apropos 検索
 C-c M-d - 関数のディスアセンブル

評価コマンド:
 C-M-x - ポイントを含むトップレベルフォームを評価
 C-x C-e - ポイントの前の S 式を評価
 C-c C-p - ポイントの前の S 式を評価し,結果を pretty-print する

xyzzy - Common Lisp なエディタ

Windows で Lisp と言えばこれ.xyzzy が素晴しいです.なんと Common Lisp (準拠度 6 割程度とのこと)を採用した高性能エディタです.

ILISP

ドキュメント

ilisp から利用可能な 1 ドキュメントとしては,

が ilisp からヘルプとして利用可能です.HyperSpec のが新しい規格書ですが,ドキュメントやサンプルが沢山あったほうが嬉しいので CLtL2 も入手しておきましょう .

ilisp の設定を済ませると,コマンド一発で CLtL2 や HyperSpec が引けるようになります.HTML を表示時に外部ブラウザが起動してうっとおしい人は lynx や w3m を使えば Emacs 内で全てが完結します.

また,通常の ilisp では関数名を入力した後のスペースで Window がポップアップして引数リストを表示してくれますが,これが邪魔という人は

(setf lisp-no-popper t)

とすればポップアップしなくなります.さらに,引数をミニバッファに表示するのすら邪魔だ,という人は

(setf ilisp-*arglist-message-lisp-space-p* nil)

で表示しないように設定できます.

ilisp 環境では

で,簡単にヘルプが引けます.

ilisp の機能

とりあえず,現状使ってる ilisp の機能.(broken?) は設定が悪いのかちゃんと動いてないやつ.(だれか教えて下さい…)

PREFIX : C-c
C-c C-s         slow-lisp               安全第一に
C-c C-f         fast-lisp               速度重視で
C-c L           cltl2-lookup            CLtL2 を引く
C-c H           hyperspec-lookup        HyperSpec を引く
C-c k           compile-file-lisp       ファイルをコンパイル
C-c l           load-file-lisp          ファイルをロード
C-c S           select-ilisp            lisp を切り替える(複数の Lisp 処理系を使ってる時とか)
C-c s           status-lisp             ilisp の状態を表示
C-c g           abort-commands-lisp     lisp に送ったコマンドを中断
C-c z           reset-ilisp             lisp の状態をリセット
C-c y           call-defun-lisp         (broken?)
C-c b           switch-to-lisp          lisp なバッファに切り換え
C-c *           Prefix Command
C-c SPC         mark-change-lisp        変更マークを付ける
C-c !           default-directory-lisp  lisp のデフォルトディレクトリを表示
C-c t           trace-defun-lisp        関数のトレース ON/OFF
C-c C-w         compile-region-and-go-lisp      リージョンをコンパイル後,lisp バッファへ移動
C-c C-n         eval-next-sexp-and-go-lisp      S 式を評価後,lisp バッファへ移動
C-c C-e         eval-defun-and-go-lisp          関数定義を評価後,lisp バッファへ移動
C-c C-r         eval-region-and-go-lisp         リージョンを評価後,lisp バッファへ移動
C-c c           compile-defun-lisp              関数定義をコンパイル
C-c C-b         ilisp-compile-buffer            バッファにあるコードをコンパイル
C-c w           compile-region-lisp             リージョン内のコードをコンパイル
C-c n           eval-next-sexp-lisp             次の S 式を評価
C-c e           eval-defun-lisp                 関数定義を評価
C-c r           eval-region-lisp                リージョンを評価
C-c ^           edit-callers-lisp               (broken?)
C-c M           macroexpand-lisp                マクロ展開
C-c m           macroexpand-1-lisp              マクロ展開(macroexpand-1 ふつーこっち)
C-c d           documentation-lisp              ドキュメント表示
C-c a           arglist-lisp                    引数リスト表示
C-c I           inspect-lisp                    インスペクタ表示
C-c i           describe-lisp                   describe する
C-c )           find-unbalanced-lisp            括弧の不一致を見つける
C-c ;           comment-region-lisp             リージョンをコメントアウト
C-c <return>    complete                        補完
C-c TAB         complete-lisp                   lisp シンボルを補完
C-c C-c         compile-defun-and-go-lisp       関数定義をコンパイル後,lisp なバッファに移動
C-c C-z         run-lisp                        lisp を起動

ESC RET         complete                        補完
ESC TAB         complete-lisp                   lisp シンボルを補完
ESC `           next-caller-lisp                (broken?)
ESC "           replace-lisp                    置換
ESC ?           search-lisp                     (broken?)
ESC .           edit-definitions-lisp           (broken?)
ESC ,           next-definition-lisp            (broken?)
ESC C-e         end-of-defun-lisp               関数定義の末尾へ移動
ESC C-a         beginning-of-defun-lisp         関数定義の先頭へ移動
ESC C-q         indent-sexp-ilisp               S 式内をインデント
ESC C-r         reposition-window-lisp          位置を再設定
ESC q           reindent-lisp                   再インデント
ESC C-x         eval-defun-lisp                 関数定義を評価

C-c * 0         clear-changes-lisp              変更マークをクリア
C-c * c         compile-changes-lisp            変更マークしたところをコンパイル
C-c * e         eval-changes-lisp               変更マークしたところを評価
C-c * l         list-changes-lisp               変更マークのリスト表示

J

Java で書かれたエディタ。