#:g1: 最古のスレッディングマクロを探す旅

Posted 2022-09-05 21:12:35 GMT

最古のスレッディングマクロを探す旅という題ですが、1980年にスレッディングマクロのアイデアが披露されていたのを発見したので、その紹介です。
1980年より古い事例が発見できたら続きを書きますが、果して見付けられるでしょうか。

ちなみにスレッディングマクロといえば、Clojureが広めたもので、色々なLisp方言でも実装が試みられています。

さて件のスレッディングマクロですが、1980年にLISP-FORUMというメーリングリストで紹介されています。

考案したのはBAK(William A. Kornfeld)氏で当初の実装は、*シンボルをsubstで置換するというものでしたが、KMP(Kent M. Pitman)氏によりlet*に展開される改善案が出ています。

Common Lispで実装するとこのような具合です。

(defmacro seq (&body body)
  `(let* (,@(mapcar (lambda (form) `(* ,form)) body))
     *))

(seq) → NIL

(seq *) → NIL

(seq * (list *))(NIL)

一見問題なさそうなのですが、前の式の値を参照する*が大抵の場合は、cl:*というスペシャル変数なので気を付けないと意図せぬ振舞いとなってしまいます。
これを改善しようとすると面倒臭いことになりますが、一応問題を解決してみましょう(※LispWorksでしか動きません)。

(defun canonicalize-bindspec (bindspec)
  (mapcar (lambda (v)
            (etypecase v
              (cons v)
              ((and symbol (not null)) `(,v nil)))) 
          bindspec))

(defun subst-symbol (new old sym) (if (string= old sym) new sym))

(defmacro foo-let* (sym (&rest bvl) &body body &environment env) (let* ((bvl (canonicalize-bindspec bvl)) (bvlhd (car bvl)) (bvltl (cdr bvl)) (newsym (make-symbol (string sym)))) `(let (,@(and bvlhd `((,(subst-symbol newsym sym (car bvlhd)) ,@(cdr bvlhd))))) ,(destructuring-bind (let* bvl . body) (walker:walk-form `(let* (,@(mapcar (lambda (v) (destructuring-bind (var . val) v `(,(subst-symbol newsym sym var) ,@val))) bvltl)) ,@body) env (lambda (sub ctx env &aux (stop? nil)) (declare (ignore env ctx)) (if (symbolp sub) (values (subst-symbol newsym sym sub) stop?) (values sub stop?)))) `(,let* ,bvl ,@body)))))

(defmacro seq (&body body) `(foo-let* * (,@(mapcar (lambda (form) `(* ,form)) body)) ,@(and body `(*))))

(seq) → NIL

(seq *) ;=== (let ((#:* *)) (let* () #:*)) → NIL

(seq * (list *)) ;=== (let ((#:* *)) (let* ((#:* (list #:*))) #:*)) (NIL)

*というシンボルを置換するのにfoo-let*というものを導入してみましたが、何にせよ七面倒臭いことになりました。

まとめ

スレッディングマクロは、アナフォリックマクロに近いところもありますが、今回のseqの仕様はスレッディングマクロと、アナフォリックマクロの中間あたりかと思います。
ちなみに、Common LispのREPLで******という直前の3つ前までの値を参照できる流儀は、MACLISP以来の伝統ですが、Interlispにも同様のものがあり、Interlispでは、*itだったようです。


HTML generated by 3bmd in LispWorks 8.0.1

comments powered by Disqus