Hatena::Groupcadr

わだばLisperになる このページをアンテナに追加 RSSフィード

2004 | 12 |
2005 | 01 | 02 | 07 | 10 | 11 |
2006 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2007 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2008 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2009 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2010 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 08 | 09 | 10 | 11 | 12 |
2011 | 01 | 02 | 03 | 04 | 05 | 06 | 07 | 11 |

2008-02-05

LISP-2とFUNCALL

| 01:05 | LISP-2とFUNCALL - わだばLisperになる を含むブックマーク はてなブックマーク - LISP-2とFUNCALL - わだばLisperになる

del.icio.us等のArc関連でブックマークされた記事を眺めていると、ArcがLISP-1で伝統的なマクロを採用したということが話題になっているようです。

確かに名前の競合に注意を払わなくてはいけないので、面倒という気がしますが、どれだけ大変になるものなのでしょう。

書いてはいけないパターンの一覧とかあると良いなあと思うのですが…。

それで、そういうことを考えていて、どんどん脱線してしまい、どういう訳かLISP-2のFUNCALLについて調べていました。

このFUNCALLですが、LISP-2のCommon Lispや、Emacs Lispではお馴染だと思います。

それで、導入されたのは、LISP OARCHI*1というMACLISPについての文献によれば、1973/9/15付けの記録で新しい関数の導入として説明されているので、1973年のようです。

導入の説明としては、

((CAR X) A B C)

と書くのも

(FUNCALL (CAR X) A B C)

と書くのも同じという説明があります。ただ、

((LAMBDA (CAR) (CAR X)) 'FOO)

のような場合、関数属性をもったシンボルだと、そっちが優先されてしまうので、意図した結果になりません。それで、

((LAMBDA (CAR) (FUNCALL CAR X)) 'FOO)

という風に書くことによって回避することができるようになる、と記録されています。

同じLISP-2である、MACLISP系のEmacs Lispでも、Common Lispでも、

((LAMBDA (CAR) (CAR X)) 'FOO)

という記述は意図した結果になりませんが、MACLISPでは、

('car '(1 2 3 4))

(#'car '(1 2 3 4))

((if t 'car 'cdr) '(1 2 3 4))

共にOKです。こういう記述をするとなんとなく見た目的にLISP-1に近いですが、

(let ((foo #'car))
  (foo '(1 2 3 4)))

は変数属性に値が入り、関数属性は空なのでエラーです。(fooが予め他で関数属性を持つ定義をされていれば、そっちが呼び出されます。)

MACLISPの場合を纏めると、

  1. リストの先頭を見て、アトムならばそのシンボルが関数属性を持つか調べ、あったらそれ以降を引数として、関数として実行。もしくはオブジェクトによりエラーとする。
  2. コンスならば、その式を評価して、結果を評価。

ということになるかと思います。

うまくオチが全く付けられないのですが、LISP-2にFUNCALLは必須というわけではなかったのか!ということに意味なく感動したので、このエントリを書いてみたのですが、どうにも纏まりませんでした…。

ちなみに、MACLISPでは、マクロ、コンパイル済み関数、依存ファイルのオートロード属性等々色々な属性がシンボルに付けられていて、それによって評価器が色々判断して動作していて、単純で分かりやすい気もします。Common Lispでは、この辺の動作は大分違っています。

*1:MITのAIラボのITSという当時メインで使われていたOS上のファイル