スクリプト言語としてのEmacs Lisp
筆者はEmacsをエディタとして使用しません。「Emacsは素晴らしいオペレーティングシステムだが、まともなテキストエディタだけが欠けている」という意見に賛成です。しかし時には、Emacsの関数ライブラリを簡単に利用できたらと思う場合もあります。Elisp (Emacsの土台であるLispインタープリタ) プログラムをEmacsの外部から実行するためには、プログラムに以下のようにシバン行をつけて実行します。
#!/usr/bin/emacs --script
これで、プログラムの残りの部分を読み込んでコードを実行するインタープリタであるPerlやPythonやRubyやBashと同じように、Emacsを動作させられます。もちろん、Emacsバイナリへの正確なパスを指定する必要があります。「/usr/bin/emacs」はOS Xと筆者が今までに使用したすべてのLinuxディストリビューションの場合で適切ですので、読者の場合も恐らくこれでいいでしょう。
Perl、Pythonなどと異なり、Lispはコメントにシャープ記号を使用しないので、Lispプログラマは先ほどのシバン行に困惑するかもしれません。しかしバージョン22以降、Emacs Lispは、PerlやPythonといったすべての他の言語と同様にシバン (シャープバン、「#!」) 行を処理するように拡張されています。古いバージョンのEmacsを使用している場合、こちらで説明されている通り、1行目がややこしくなります。
[「#!」はUnixの歴史を遠く遡る事情に由来するマジックナンバーです。Wikipediaにはシバン行専用のページまであります]
Emacsが本当に秀でている1つの分野は、日付の操作と変換です。Emacsのカレンダー関数はEdward ReingoldとNachum Dershowitzにより記述されました。この2人のコンピュータ科学者は暦算に関し、いくつかの論文のほかに、書籍も執筆しました。筆者はこの書籍の以前の版を持っていますが、それも今ではGoogle Booksにあります。また、Reingoldのサイトから元の論文のPostScript版を入手することもできます。
ReingoldとDershowitzは非常に優れた書き手であり、2人の暦に関する文章を読んでみれば、暦について多くを知ることができるばかりではなく、ごく単純な要素から複雑なプログラムを構築する方法も学べます。
以下は、グレゴリオ暦の日付を他のいくつかの暦に変換するElispプログラムのソースコードです。Emacsの強力なカレンダー関数のおかげで、スクリプトはとても短くなっています。
#!/usr/bin/emacs --script
(require 'calendar)
; 日付がコマンドラインで与えられなかった場合、現在の日付を使用する
(if (= 3 (length command-line-args-left))
(setq my-date (mapcar 'string-to-int command-line-args-left))
(setq my-date (calendar-current-date)))
; 変換を行って結果を出力する
(princ
(concat
"Gregorian: " (calendar-date-string my-date) "\n"
" ISO: " (calendar-iso-date-string my-date) "\n"
" Julian: " (calendar-julian-date-string my-date) "\n"
" Hebrew: " (calendar-hebrew-date-string my-date) "\n"
" Islamic: " (calendar-islamic-date-string my-date) "\n"
" Chinese: " (calendar-chinese-date-string my-date) "\n"
" Mayan: " (calendar-mayan-date-string my-date) "\n" ))
Lispは読解が困難との評判がありますが、いくつかの事柄を理解してしまえばさほど難しくありません。
1. 関数呼び出しはALGOLベースの言語とは異なる場所に丸括弧を置きます。以下のように記述します。
(関数 引数)
以下のようには記述しません。
関数(引数)
2. 引数はカンマではなく空白により区切られます。そのため、3つの引数を持つ関数は以下のように呼び出されます。
(関数 引数1 引数2 引数3)
3. 普通ならば演算子として扱われるものまで、すべてが関数です。そのため、以下のように記述します。
(+ 2 2)
以下のようには記述しません。
2 + 2
4. 関数は値を返します。返り値は関数で囲むことにより操作できます。以下のようなものが一般的に見受けられます。
(関数3 (関数2 (関数1 引数)))
この場合、関数は1、2、3の順に適用されます。
筆者のスクリプトの3行目では、ReingoldとDershowitzのカレンダーライブラリをインポートしています。6行目から8行目はプログラムに渡されたコマンドライン引数を処理します (後述)。組み込みElisp変数「command-line-args-left」は、文字列としてスクリプトに渡された引数のリストです。14行目から19行目は、リスト化された6つの暦への変換を実際に行います。12行目は日付文字列を連結し、11行目はそれらを出力します。
筆者はこのプログラムを「date-convert」と命名し、「$PATH」に含まれる「~/bin」ディレクトリに置きました。以下のように引数をつけずに呼び出した場合、
date-convert
7種類の暦で現在の日付を出力します。
Gregorian: Tuesday, April 8, 2008
ISO: Day 2 of week 15 of 2008
Julian: March 26, 2008
Hebrew: Nisan 3, 5768
Islamic: Rabi II 1, 1429
Chinese: Cycle 78, year 25 (Wu-Zi), month 3 (Bing-Chen), day 3 (Wu-Yin)
Mayan: Long count = 12.19.15.4.2; tzolkin = 2 Ik; haab = 5 Pop
3つの数値パラメータ (月、日、年) をつけて呼び出すと、その日付を先ほどの7種類の暦で出力します。そのため、
date-convert 6 6 1945
は以下の結果になります。
Gregorian: Wednesday, June 6, 1945
ISO: Day 3 of week 23 of 1945
Julian: May 24, 1945
Hebrew: Sivan 25, 5705
Islamic: Jumada II 24, 1364
Chinese: Cycle 77, year 22 (Yi-You), month 4 (Xin-Si), day 26 (Bing-Wu)
Mayan: Long count = 12.16.11.8.10; tzolkin = 8 Oc; haab = 8 Zip
3つよりも多い、または少ない引数を指定すると、引数を指定しなかった場合と同じように振る舞い、現在の日付を出力します。数字ではなく文字などの無意味な引数を指定すると、カレンダーライブラリからのエラーメッセージを出力します。このような単純なスクリプトの場合、エラー処理を念入りに作ることにはあまり意味がないと思います。不適切な引数を指定しても世界が滅びるわけではないのです。
スクリプトを変更して変換結果を多くしたり少なくしたりすることができます。ライブラリはフランス革命暦、ペルシャ暦、コプト暦、エチオピア暦も処理できます。
数多くの非常によくできたライブラリ類がElispで開発されてきました。たとえテキストエディタとしてのEmacsが嫌いであっても、Emacsをインタープリタとして使用すれば、それらを利用することが可能です。
追記
後の記事では今回のスクリプトをCGIスクリプトに作り替えます。
【トップへ】
公開日:2012年11月6日
この文書は『And now it’s all this』の項目「Emacs Lisp as a scripting language」の日本語訳であり、
クリエイティブ・コモンズ 表示 - 継承 3.0 非移植 (CC BY-SA 3.0)の下で利用可能です。