#:g1: Allegro CLのdeftransform

Posted 2022-09-12 18:18:01 GMT

以前、Allegro CLをいじっていて、Allegro CLにもdeftransformのような機構があるらしいことを見付けていたのですが、深追いはしたことがありませんでした。
今回は気が向いたのでAllegro CLでのdeftransformがどういう具合なのか探ってみたいと思います。

ちなみに、deftransformというのは、コンパイラマクロの親戚のようなもので、よりコンパイラの内部処理で機能するものです。
Lisp界隈では、1980年代初頭にコンパイラ技術の発展が著しい時期があったのですが、その辺りで登場した模様です。

deftransformで定義したソース変形は大抵の場合は多段フィルターで構成され、変形に失敗した場合は、打ち切りフラグを出力して後段に処理を流すということが多いかと思います。

Allegro CLのdeftransform

さて、Allegro CLのdeftransformですが、シンボルの属性リストにソース変形の関数が仕込まれているようです。ちなみにLispWorksなどもこの方式です。
excl::.nl-transform.という属性で検索すると、ソース変形が設定されている関数が観察できます。

(do-symbols (s :excl)
  (when (get s 'excl::.nl-transform.)
    (print (list s
                 (get s 'excl::.nl-transform.)))))

しばらく処理系を突いてみてdeftransformに相当するものを探してみたところ、def-trというものを見付けました。
ちなみに、こういうものを探す場合には、cl-ppcreのregex-apropos等が便利です。

(remove-if-not #'macro-function (ppcre:regex-apropos-list "^def"))

ドキュメントはありませんが、def-trのマクロ展開を確認しつつ実際に試してみましょう。

(defun foo ()
  0)

;;; def-tr transform-name function-name (args*)
(compiler::def-tr ret42 foo ()
  42)

(funcall (lambda () (foo)))
→ 0

(funcall (compile nil '(lambda () (foo)))) → 42

うまく動いているようです。
上記の例では打ち切りをしていませんが、打ち切りには、(excl::no-transform)を使うようです。

(compiler::def-tr ret42 foo ()
  (excl::no-transform))

(funcall (compile nil '(lambda () (foo)))) → 0

まとめ

今回の例では、Common Lisp標準のコンパイラマクロ以上のことはできていませんが、deftransformではコンパイル時の内部表現が利用できることが多いため、引数の型で処理を切り替えたりすることが可能なことが多いかと思います。
私の知っている範囲では、deftransformについては、SBCLの機能が一番充実していますが、メジャーな処理系は大抵装備しているもののようです。


HTML generated by 3bmd in LispWorks 8.0.1

comments powered by Disqus