2008年12月28日日曜日

2008年12月26日金曜日

'fooと#'fooの違いは環境の違い

QUOTEとFUNCTIONを使い分ける:もう少し詳しい説明 -- 逆引きCommonLisp

をぼんやり見ていて、そういえば FUNCTION と COERCE では環境が違うってうちの CLISP が言ってたのを思い出した。

(funcall '(lambda (x) (1+ x)) 1)
;; => Error
;; *** - FUNCALL: argument (LAMBDA (X) (1+ X)) is not a function.
;;       To get a function in the current environment, write (FUNCTION ...).
;;       To get a function in the global environment, write (COERCE '... 'FUNCTION).

CLHS にもそれらしい記述があったのでメモ。

CLHS: Function COERCE
If the result-type is function, and object is any function name that is fbound but that is globally defined neither as a macro name nor as a special operator, then the result is the functional value of object. If the result-type is function, and object is a lambda expression, then the result is a closure of object in the null lexical environment.

= objectがマクロ、スペシャル・オペレータ以外でグローバルに定義されたfboundな関数名を持っているなら、そのobjectの関数値を返す。 objectがラムダ式なら、空レキシカル環境なobjectのクロージャを返す。

CLHS: Special Operator FUNCTION
The value of function is the functional value of name in the current lexical environment.

= functionは現在のレキシカルな環境を持ったnameの関数値を返す。

この環境を引数に渡せる関数、マクロはいくつかある。 ラムダリストキーワードに &environment を持つものがそれで、例えば setf とか push とか。

(arglist 'setf)
;=> (&WHOLE SYSTEM::WHOLE-FORM &REST SYSTEM::ARGS &ENVIRONMENT SYSTEM::ENV)

macroexpand も環境を引数に渡せるが、こちらはなぜか &optional になっている。

(arglist 'macroexpand)
;=> (FORM &OPTIONAL ENV)

2008年12月19日金曜日

あと一週間

万能プレーヤーである VLC media player の起動アイコンがクリスマス仕様になっている事に気づいた。

Google のトップページが時期によって模様替えされるのは何度か見たけれど、こういう遊びをするソフトウェアって少ないんじゃないかな。

2008年12月18日木曜日

おおえまくすよ マクロをつかわないとは なさけない

(require 'cl) は悪なのか?の続き。

気が向いたので軽く調べてみた。

---

GNU Emacs のマニュアルには以下のような注意書きがある。

Common Lisp Extensions Overview
Please note: the CL functions are not standard parts of the Emacs Lisp name space, so it is legitimate for users to define them with other, conflicting meanings. To avoid conflicting with those user activities, we have a policy that packages installed in Emacs must not load CL at run time. (It is ok for them to load CL at compile time only, with eval-when-compile, and use the macros it provides.) If you are writing packages that you plan to distribute and invite widespread use for, you might want to observe the same rule.

どうやら Emacs 実行時の cl パッケージ読み込みは禁止されていて、コンパイル時のマクロ展開に限って読み込みを許可しているらしい。つまり (require 'cl) ではなくて (eval-when-compile (require 'cl)) を使いなさいってことか。

コンパイル時にマクロ展開をしなければならないのは Common Lisp でも同じだから、この点は納得。

the CL functions are not standard parts of the Emacs Lisp name space

これは「名前には接頭辞を付けろ」という elisp のコーディング規則に反しているから関数上書きしないように気をつけてね、そんな意味でしょうか。

んー、名前空間の話は cl パッケージを読み込んだ時点でユーザは承知していると思うんだが。

ありがたいことに elisp のマクロは CL のマクロと(ほぼ)同等の機能があるのだから、マクロによる抽象化によってソースコードが短く、より簡素になるなら利用しない手はない。見やすいコードとそうでないコード、どっちを書きたい?と質問するようなもの。

…というのが自分の意見です。

所詮 .emacs 位しか書いたことのない学生の意見ですから反論は認めます。mew の作者さんのように何かしらの elisp パッケージを作成した方は、きっとこの cl パッケージのおかげで互換性等々に苦労されたんだと思いますし。

まとめ、あるいは教訓:

  • cl パッケージを利用するファイルは、必ずコンパイルして実行時にそれに依存しない形にすること。(eval-when-compile (require 'cl)) 用法用量を守って正しく使いましょう。
  • マニュアルはなるべく最新のものを参照すること。OSS のマニュアルの邦訳がメンテナンスされないのはよくある話。

おまけ:

「マクロではなく cl.el の関数群を使いたいときはどうすれば?」と質問された時の Stallman 氏の返事

Installed Lisp packages must not use those functions.

2008年12月15日月曜日

[Emacs] newLISP 環境を構築してみたい

[追記@2009-04-20T03:29:05]
もう少し拡張したものを置いておきます。
http://github.com/kosh04/newlisp-files/tree/master


Emacs から newLISP のプロセスを操作する関数群を書いたのでちょっと醸してみます。

もともと xyzzylisp 用に作ったんだけど、やっぱり資産がある elisp の方が短くできてしまったので。

使い方:

  1. 以下の URL のコードを newlisp.el で保存して eval-buffer
    http://paste.lisp.org/display/72178
  2. 必要に応じて、以下の変数を書き換え。
    • newlisp バイナリのパス名: *newlisp-command*
    • プロセス間文字コード: *newlisp-process-coding-system*
    Windows インストーラから newLISP をインストールした場合は、環境変数 NEWLISPDIR が設定されているはずなのでパス名はそのままで大丈夫だと思います。 newlisp バイナリには utf-8 が使える版と使えない版があるので、ここではマルチバイト文字を扱える utf-8 版を推奨します。 →[xyzzy] newLISP 環境を構築してみたい
  3. 後のS式操作はカンでお願いします。スクラッチバッファで遊んだことがある人ならたぶん分かるでしょう。 主に使うのは newlisp-eval-last-sexpnewlisp-show-repl くらいでしょうか。

残念ながらハイライトなどのリッチな機能はありません。

あ...それと (require 'cl) が必要かもしれないです。


Emacs(VineLinux4.2) だとなぜか評価のタイミングがずれました。
(一回目の newlisp-eval-last-sexp では何も表示されないで、二回目でまとめて出力されてしまう)
NTEmacs では問題なく動いたので、 Emacs 側の問題?

(require 'cl) は悪なのか?

自分の中で Emacs Lisp の CL パッケージの評判があまりよろしくない印象なんだが、はっきりした理由を聞いたことがないなあ。

気が向いたらまとめのページが無いか詮索してみよう。

詮索した。

elisp にもラベル記法があったのか

(let ((print-circle t)
      (lst '(7 8 3 9 4 0 1 6 5 2)))
  (princ (list (sort lst #'<) lst))
  (terpri))
;-> ((0 1 2 3 4 5 6 . #1=(7 8 9)) #1#)
;=> t

((lambda (x)
   ((lambda (y1)
      ((lambda (&optional y2)
         ((lambda (z)
            (list x y1 y2 z))
          (car (cdr #1=(cdr #2='(1 (2) 3))))))
       (car (cdr #3=(car #1#)))))
    (car #3#)))
 (car #2#))
;=> (1 2 nil 3)

;; 上のコードは少し古い destructuring-bind のマクロ展開 (CL)
(macroexpand '(destructuring-bind (x (y1 &optional y2) z) '(1 (2) 3)
                (list x y1 y2 z)))

Emacs Lisp はかなり Common Lisp に近い仕様なんだなと改めて思った。
# もちろん動的スコープだとかクロージャが無いとかツッコミはあるけど :-)

しかしこの書き方 (#n#) の名称なんだっけ...


CLtL2, CLHS をパッと見たけど 「#n# 構文 (#n# syntax)」としか書いてなかった。

あと、影響を受けたのは CL より Maclisp 方言か。歴史知らなさ過ぎかもしれない。