&AUXの謎 — #:g1

Posted 2011-12-04 09:08:00 GMT

自分が抱いているLISPの謎の一つに「LETがあるのに何故&AUXが存在しているのか」というものがあります。
LETも&AUXも70年代後半にLispマシンに導入されたのが最初のようですが、MIT CADRLispマシンのソースを眺めていると、どうもLETより、&AUXの方が導入が早かったんじゃないだろうか、と思わせるところがあります。
自分の推理としては、&AUXより汎用的なLETがある環境にわざわざ&AUXを導入しようとは思わないだろう、ということで、&AUXが最初に導入されている環境に後でLETが導入されたので&AUXが生き残ることになったのではないか(既存のコードとの互換性等のため)と考えていました。
&AUXとLETの関係については割とFAQで、ニュースグループなどでも時折質問をみかけます。
最近、そんな質問の一つをふと眺めていたのですが、Lispマシン開発に携わっていたDaniel Weinreb氏のポストに&AUXとLETの導入についての解説がありました。

これによると
&AUX actually predates LET.  &AUX, along with &OPTIONAL and &REST, was
introduced into the MIT Lisp Machine dialect (later known as Zetalisp)
sometime prior to the summer of 1976 (by Richard Greenblatt).  All of
these &-keywords were borrowed from MDL (a.k.a Muddle), a very unusual
dialect of Lisp used by a small group at MIT's Project MAC, in which
they were written with double-quotes instead of the ampersand, e.g.
"OPTIONAL", "AUX".

They were backmigrated into Maclisp some years later. They were never in Interlisp or Scheme.

At that time (1976), LET had not been codified as part of the language; many people at MIT had their own LET-like macros, all slightly different and incompatible. Soon thereafter, someone (probably Dave Moon) picked the current LET syntax and installed it as part of the basic Lisp system, implemented (originally) as a macro that expanded into a lambda-combination. This was one of the first times a macro had been installed as part of the Lisp system itself.

とのことで、1976年にMDLからlambdaキーワードが導入され、その後でLETが導入されたということです。
ちなみに、MDLとはどんな感じのものかというと
<DEFINE FIB (N "OPTIONAL" (A1 1) (A2 0))
  <COND (<0? .N> 0)
        (<1? .N> .A1)
        (ELSE <L? .N 2>
              <FIB <- .N 1>
                   <+ .A1 .A2>
                   .A1>)>>
という感じに不思議な書法のLISP方言で、CLのlambdaリストキーワードが、MDL由来だというのは、The Evolution of Lispにも詳しいところです。また、Schemeの述語の?もMDLから来ていたり、ZorkはMDLで書かれていたりで、言語自体は有名ではないですが謎の影響力を持つ言語のようです。ちょっと見たところでは、CLの型宣言もMDLの宣言に似ています。

さて、1976年辺りの出来事とのことなので、その辺りのファイルを探して眺めていたのですが、1976/5/1日の日付のファイルで面白いものを見付けました。
;; >lispm1>nrev~&.delq 1976-05-01 23:31

(DEFUN DELQ (X Y "OPTIONAL" (N 10000000)) (DO ((J N (1- J)) (Z Y (CDR Z))) ((OR (ZEROP J) (NULL Z)) Z) (OR (EQ (CAR Z) X) (RETURN (DO ((W Z (CDR W)) (K J (COND ((EQ (CADR W) X) (1- K)) (T K))) (N)) ((OR (ZEROP K) (NULL (CDR W))) Z) (AND (EQ (CADR W) X) (SETQ N (%CDRC W)) (COND ((ZEROP N) (RPLACD W (CDDR W))) ((= N 3) ((LAMBDA (S) (%SCDRC (CDR W) 1) (%SCDRC W 0) (RPLACD W S)) (CDDR W))))))))))

このDELQの定義なのですが、&OPTIONALの代りに"OPTIONAL"が使われていて、MDLそのままです。また、LETの代りにLAMBDAでローカル変数を束縛しています。
時期的にもWeinreb氏の示している時期とも一致しますが、当初"OPTIONAL"形式がそのまま導入され、それから&OPTIONALになったのかもしれません。
何故"&"がつくことになったのかは謎ですが…

ちなみに、上記のスレッドでも言及があるのですが、Common Lispでは、&AUXがLETで置き換えることができないポイントが一つあります。BOA Lambda Listと呼ばれているもので、
(defstruct (foo
            (:constructor mkfoo (x y &aux (x (* x 2)) (y (+ x y))))
            (:predicate foo?)
            (:conc-name ""))
  x y)

(mkfoo 1 1) ;=> #S(FOO :X 2 :Y 3)

こんな感じに、コンストラクタの引数をスロットに反映させたり、他のスロットの値をもとに初期化したりするのに使うのですが、これは、LETで置き換えることができません。
しかし、どうも70年代後半のLispマシンのdefstructにはこういう構文がないようなので、Lisp machine lispの後期か、Common Lispあたりで導入されたのかなと推測しているところです。
この辺りも調べてはっきりさせてみたいところです。

comments powered by Disqus