2014-07-20

"Emacs Lisp テクニックバイブル" るびきち 著

本書は、Lisp を手軽に学ぶために手にしたのだが、仕事仲間に話題を振ると、エディタ談義で盛り上がってしまった。プログラミング言語とエディタには相関関係があるという説もあるが、無理に法則性を見出すこともあるまい。開発環境は開発者の思考の場であり、テキストエディタは思考プロセスを書きとめる上で最も単純で根幹的な道具となる。それだけに使い手の思い入れは強く、プログラミング言語同様、宗教的ですらある。むかーし、出張先で困らないように、最低でも vi ぐらいは使えないといけないよ!と指摘されたことがある。もうそんな時代でもあるまいが、どんな環境でも対応できるような身体にはしておきたい。
本格的にエディタの選択に迫られたのは、20年前になろうか。Emacs に近寄り難いと感じたのは、当時のデフォルトのキーバインドが酷かったこと。vi の方がましだと思ったぐらい。現在でも、Emacs のキーバインドにうろたえる人は少なくあるまい。ネット社会ともなれば、カスタマイズした設定ファイルを公開してくれる方々がいて、非常に助かる。shell環境もそうだが、この手の設定環境は伝承される傾向があり、情報不足に陥ることはなさそうだ。
とはいえ、デフォルトで使いづらいというだけで、ヤル気が失せる。編集作業において、キーワードの補完や色分けといった機能は必須だ。コーディング中に、変数名の綴りを間違うだけで大きなストレスとなる。ちなみに、Emacs では、テキストの色分け機能がデフォルトで無効になっているという。(require 'generic-x)ってやれば済む話だが。著者は、これだけで Emacs ユーザの損失だと嘆いている。そうだろう!そうだろう!てなわけで、おいらは秀丸エディタ派となった。なんにせよ、テキストエディタってやつは、料理人でいうところの包丁一本... の存在だ!

しかしながら、プラットフォームに依存しない作業環境という観点から、Emacs も捨てがたい。たまには、Emacs + Mew を使うし、TRAMP というリモートアクセス用のパッケージにも興味がある。Windows版や Mac版もあるにはあるが、一昔前はバージョンや OS の違いで互換性が保たれないという印象があった。現在ではそうでもないらしい。
Emacs のマクロ機能は、秀丸エディタのそれとは比べ物にならないのも確か。一つのエディタの中に作業環境を押し込むのもどうか?という疑問もあるが、Emacs はエディタの概念をも超越している。実際、エディタの外に、gcc, Ruby, HTML & JavaScript などの環境を並行して構築しているが、プラットフォームを Emacs で吸収するという考え方もあるだろう。それを実現させるものが、バッファの概念だ。初めて触れた時、そのエレガントな思想に感動したものである。ファイルから独立したバッファの抽象度は高く、作業領域やアプリケーション領域に割り当てることができる。
ざっと眺めるだけでも... コマンドや関数の補完では、Completions バッファが自動で開いて候補が表示される。Help を開けば、そこに表示用バッファが生成される。ファイルを探す時(find-file)、カーソルでディレクトリ階層を辿ることができる。shell との相性がよく、端末として使える。本書は、eshellってやつを紹介してくれるが、病みつきになるらしい。なによりも驚くべきは、一時的な作業領域の scratch バッファが、lisp式を評価する機構を具えていることだ。あるいは、Lisp用対話型インタプリタも用意されている。本書では、これらよりもっといいやり方を教えてくれるけど...
それにしても、秀丸エディタのタブモードは捨てられん!と思いきや、Emacs にもあった。tabbar.elってやつが...

さて、Emacs Lisp の方はというと、ちと印象が違う。多少の方言は覚悟しても、Common Lisp の簡易版ぐらいに思っていたのだが、本書は決定的な違いがあることを教えてくれる。その違いとは、グローバル変数やクロージャの思想、そして、Common Lisp がレキシカルスコープであるのに対し、Emacs Lisp はダイナミックスコープだということ。
例えば... 関数もどきの let ってやつは、Common Lisp ではレキシカルスコープだが、Emacs Lisp ではダイナミックスコープになるんだとか... おいおい!!!
Common Lisp の機能を提供するパッケージ(cl.el)ってやつもあるが、禁止事項があって制限が設けられているという。著者は、そんな無駄なことを... と愚痴を語ってくれる。ソフトウェアを使う上で、達人の愚痴ほど参考になるものはあるまい。Emacs Lisp の進化過程では、Common Lisp の機能から派生したものが多い。昔は、when すらなかったとか。徐々に Common Lisp に近づいていくとすれば、制限することになんの意味があるのか、と疑問を持つのも当然であろう。実際、cl.el は標準装備され、(require 'cl)ってやるだけで使える。Lispユーザは当たり前のように使っているそうな。いくら制限を設けても、民主主義によって淘汰されていくだろう。
また、Emacs lisp はシングルスレッドだが、emacs 自体はマルチスレッドで、擬似マルチスレッドプログラミングのための deferred.el というライブラリも紹介してくれる。

1. Emacs Lisp のためのパッケージ... auto-install.el
auto-install.el は、URLを指定するだけでネット上の Emacs Lisp プログラムをインストールできるようになるという。尚、EmacsWiki(http://www.emacswiki.org/)には、様々なパッケージが集められている。

$ mkdir -p ~/.emacs.d/auto-install
$ cd ~/.emacs.d/auto-install/
$ wget http://www.emacswiki.org/emacs/download/auto-install.el
$ emacs --batch -Q -f batch-byte-compile auto-install.el

.emacs.el
(add-to-list 'load-path "~/.emacs.d/auto-install/")
(require 'auto-install)
(auto-install-update-emacswiki-package-name t)
(auto-install-compatibility-setup)
(setq ediff-window-setup-function 'ediff-setup-windows-plain)

他にも、Lisp 使いに便利そうな5つのパッケージを紹介してくれる。
  open-junk-file.el          (試行錯誤用ファイルを開く)
  lispxmp.el                 (式の評価結果を注釈する)
  paredit.el                 (括弧の対応を保持して編集する)
  auto-async-byte-compile.el (保存時に自動バイトコンパイル)
  package.el                 (ELPA/Marmaladeインストーラ emacs24で標準)

ダウンロードは...
M-x install-elisp-from-emacswiki open-junk-file.el
M-x install-elisp-from-emacswiki lispxmp.el
M-x install-elisp http://mumble.net/~campbell/emacs/paredit.el
M-x install-elisp-from-emacswiki auto-async-byte-compile.el

ついでに、tabbar.el も...
M-x install-elisp-from-emacswiki tabbar.el
それぞれダウンロード後にファイルがポップアップするので、C-c C-c とすればインストール完了。

2. Lisp式の評価方法
対話的に評価できる方法が二つあるという。一つは、scratch バッファを使う方法。二つは、ielm(Interactive Emacs Lisp Mode)を使う方法。
scratch バッファでは、eval-print-last-sexp コマンドで直下に評価結果が出力される。eval-last-sexp でも評価できるが、出力場所がコマンドライン上で少し遠い。尚、eval-print-last-sexp には C-j が、eval-last-sexp には C-x C-e がキーバインドされている。
ielm は対話型インタプリタで、Rubyで言うところの irb(Interactive Ruby)か。M-x ielm とやれば起動する。
この二つだけでも感動しているというのに、本書はもっといいやり方を教えてくれる。上記の方法は、Emacs を終了すると結果が消える。そこで、open-junk-file.el パッケージを用いれば、ジャンクファイル上で評価して自動保存できる。ジャンクファイルとは、日時を元にしたファイル名をもつファイルのことで、M-x open-junk-file ってやれば起動する。惚れっぽい酔っ払いは、ジャンクにイチコロよ!

3. Common Lispパッケージ... cl.el
関数の名前空間は、Common Lisp と Emacs Lisp に違いがあって、衝突の可能性がある。なので、cl.el の禁止事項は、eval-when-compile でバイトコンパイル時にロードしてマクロを使う分には許可するが、Common Lisp の関数は使うな!ということらしい。つまり、(require 'cl) が禁止ということか?
本書は、(eval-when-compile (require 'cl)) ってやれば、Common Lisp のマクロを合法的に使えるとしている。ランタイムに cl.el のロードが禁止となれば関数は使えないが、コンパイル時に展開されるマクロならOKってか?ん~... 解釈の問題のような気もするが...
今となっては、Common Lisp に総入れ替えするわけにもいかないだろう。古い資産が誤動作しそうだし。Common Lisp と Emacs Lisp で、レキシカルスコープとダイナミックスコープの違いがあるのも、関数の変数をめぐって大きな問題となりそうだ。ならば、(require 'cl)を許可して、Common Lisp でオーバライドさせることを明示すれば良さそうな気もするが...
それはともかく、本書で紹介されるマクロは、なかなか便利そうである。リスト構造を分解して変数に代入する時、car, nth が冗長的なので、destructure-bind を使うとすっきりする。汎変数を使うと、代入の概念を拡張できる。setq は、その拡張版の setf が使える。汎変数には、car, nth といったリスト要素だけでなく、buffer-substring, point といったバッファ関連もあるようだ。
let/let* のレキシカルスコープ版は、lexical-let/lexical-let* があるという。ん~、これは微妙だなぁ!他には構造体が使えたり...
本書は、loop マクロをかなり丁寧に解説してくれる。こいつは、Common Lisp が提供するモンスターマクロだという。リストやベクタの要素の合計/最大値/最小値を与えたり、各要素に関数を適用したり、条件を満たす要素を抽出して演算を施したり... などの演算節が豊富で、統計情報を処理するのに強力なツールとなる。連想リストやハッシュテーブルのキーを求めたり、フィボナッチ数列を求めたりするのも、エレガントに書けるという。
また、非局所脱出メカニズムには二つあるという。Emacs Lisp 本来の catch/throw と Common Lisp の block/return-from。Common Lisp には block の概念があり、明示しなくても暗黙に block が形成される。この block がレキシカルスコープを実現している。block からは、return-from で脱出できる。一方、catch はダイナミックスコープの場合で、脱出時には、throw を呼び出す。cl.el のおかげで、Emacs Lisp でも block/return-from の仕掛けが使えるというわけか。

4. eshell のすゝめ
eshell は、Emacs Lisp で書かれているために、プラットフォームに依存しないという。zsh ライクで、使い勝手もよさそう。普通のシェルはC言語などで書かれているため、シェルスクリプトの範囲でしか拡張できないが、eshell はコマンド解釈の部分ですら乗っ取ることが可能で、コマンドラインを丸ごと zsh や Ruby に渡して実行することができるという。おぉ~...

0 コメント:

コメントを投稿