#:g1: setf系アイデアの最終形態: letf

Posted 2018-12-08 19:29:08 GMT

Lisp SETF Advent Calendar 2018 9日目 》

今回は、また毛色を変えて、setf系の面白構文を紹介したいと思います。

letf

letfは、Lisp Machine Lispに存在したletsetfが合体したような構文です。
束縛系構文なので、代入系のsetfとはちょっと違うのですが、こんな感じで使えます。

(defstruct s x y z)

(let ((s (make-s :x 0 :y 1 :z 2))) (letf (((s-x s) 42)) (print s) (list s (s-x s) (s-y s) (s-z s)))) ▻ #S(s :x 42 :y 1 :z 2)(#S(s :x 0 :y 1 :z 2) 42 1 2)

letの変数部分が、setfでいう一般化変数になっていて、上記の場合は、letfのボディの中では構造体sxスロットは42になっていますが、スコープを抜ければ復帰します。

Lisp Machine Lispでは、ロカティブという参照の仕組みがありますが、ロカティブをすげかえる仕組みがマシンのメモリ参照のレベルで実装されていて、この機能によってCommon Lispでいうスペシャル変数のような感じで色々なものの参照を扱えるのですが、letfはこれを活用しています。

Common LispでもLispWorksのような一部の処理系には、letfがユーティリティとして含まれていますが、代入して元に戻すフォームをunwind-protectで囲んだ実装です。

Emacs Lispのcl.elにも何故かletfがありますが、こちらも代入して復帰となっています。
※註: Common Lispにはletfはありません。

なお、代入して元に戻す方式と、スペシャル変数のようなバインディング方式の違いですが、マルチプロセス時等に挙動が変ってきます。

また、letfで扱えるのは、ロカティブのみです。
setfでは読み出しと書き込みで整合性がなかったり非対称なものを定義できますが、こういうものはletfでは扱えません。

参考


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus