#:g1: 拡張setf定義を眺める: 制御構造篇

Posted 2018-12-17 00:05:13 GMT

Lisp SETF Advent Calendar 2018 17日目 》

今回は、処理系拡張のsetfのうち制御構造の拡張を眺めてみたいと思います。

処理系拡張のsetfとは

Common Lispの処理系には、setfの拡張が許されていますが、殆ど拡張は入れてない処理系から突飛なものを入れている処理系まで様々です。

CLISPに結構拡張が入っているので、今回はCLISPを中心に眺めてみます。

(setf if)

setfifが使えるのですが、そこそこ便利かもしれません。
ifを使ったマクロ展開がされてもsetfの場所として有効なので、言語コアでsetf展開が可能だと、かなり拡張されることになります。

(let ((x 0)
      (y 1))
  (incf (if (< x y) x y))
  (list x y))(1 1)

(let ((x nil)
      (y 1))
  (incf (or x y))
  (list x y))

展開はこんな感じです

(let* ((#:cond-29533 (< x y)) (#:new-29534 (+ (if #:cond-29533 x y) 1)))
  (if #:cond-29533
      (setq x #:new-29534)
      (setq y #:new-29534)))

(setf progn)

prognも言語のコアなので、これもsetf化の底上げになります。

(let ((x 0)
      (y 0)
      (z 0))
  (incf (progn x y z))
  (list x y z))(0 0 1)

(setf locally)

locallyも言語のコアなので、マクロ展開の結果への適用を考えているのだと思いますが、theの代わりに使える気もします。

(let ((x 0)
      (y 1)
      (z 2))
  (setf (locally (declare (fixnum x y z ))
          (values x y z))
        (values 1 1 1))
  (list x y z))(1 1 1)

(setf funcall)

規格では、(setf apply)が使えるので、ちょっとした変種というところです。

(let ((u (list 0 1 2)))
  (incf (funcall #'cadr u))
  u)(0 2 2)

(setf let)

ここからはLisp Machine Lispに実装されていたものですが、locative(参照)が扱えるので、かなり妙なことが可能です。

(let ((x 0)
      f)
  (setf (let ((x x))
          (setq f (lambda () x))
          x)
        42)
  (list x (funcall f)))(0 42)

上記の(setf let)内のxは外側のxをシャドウしていますが、末尾でx変数を返しているので、その参照に42を代入しています。
スコープの外から代入できてる感じなのがエグいですが、ここまで極端な使い方は想定していなそうではあります。

(setf setq)

これはLisp Machine Lispでも有効になっていませんが、コードの断片があるので有効にしてみると、

(let ((x 0)
      (y (list 0 1 2)))
  (setf (setq x (car y)) 42)
  (list x y))(42 (42 1 2))

こんなことを考えていたようです。
setqの場合は、値の方の参照に代入します。なかなかエグい。

まとめ

役に立ちそうなものから、面白機能なものまで紹介してみました。
次回は、リスト操作系の拡張を紹介してみたいと思います。


HTML generated by 3bmd in LispWorks 7.0.0

comments powered by Disqus