CLでSRFI-10 — #:g1

Posted 2011-06-08 10:47:00 GMT

きまぐれでCLに移植しているSRFIですが今回は、#,外部フォームです。
- srfi-10.
- (http://srfi.schemers.org/srfi-10/srfi-10.html)
#,はリーダーマクロですが、CLの#.(リード時EVAL)に似た感じのものです。
違いとしては、CLの#.は後続の式をEVALしますが、SRFI-10の#,はAPPLYします。
ちなみに、#,はCLtL1やZetalispでは、ロード時評価のリーダーマクロでしたがANSI CLでは、load-time-valueに置き換えられて廃止になっています。
下準備

(srfi-10:enable-read-time-application)
(import 'srfi-10:define-reader-ctor)
;; CLの #.
#.(+ 3 (+ (+ 3 3) 3))
;=> 12

;; SRFI-10の#, (define-reader-ctor '+ #'+)

#,(+ 3 #,(+ #,(+ 3 3) 3)) ;=> 12

そのままでは、式のCDRが再帰的に評価されていかないので#,をネストしたりする必要があります。

単純なリード時の評価以外の主な応用としては、構造体などの簡便な表記などがあるようです。
(defstruct foo x y z)

(define-reader-ctor 'foo #'make-foo)

#,(foo :x 1 :z 2 :y 3) ;=> #S(FOO :X 1 :Y 3 :Z 2)

(defstruct bar x y z)

(define-reader-ctor 'bar (lambda (x y z) (make-bar :x x :y y :z z)))

#,(bar 1 2 3) ;=> #S(BAR :X 1 :Y 2 :Z 3)

クラスにreader-ctorを定義して、さらにprint-objectも設定してみる
(defclass baz ()
  ((x :initarg :x)
   (y :initarg :y)
   (z :initarg :z)))

(define-reader-ctor 'baz (lambda (&rest args) (apply #'make-instance 'baz args)))

(defmethod print-object ((obj baz) stream) (with-slots (x y z) obj (format stream "#,(BAZ :x ~S :y ~S :z ~S)" x y z)))

#,(baz :x 1 :y 2 :z 3) ;=> #,(BAZ :x 1 :y 2 :z 3)


移植について

SRFI-10の文献だけだと微妙な挙動が分からなかったためGaucheで動作を確認して大体のところはGaucheと同じような挙動にしました。
関数のルックアップは、シンボルのSYMBOL-FUNCTIONを見るようにもしてみましたが、これもGaucheの動作に合せてdefine-reader-ctorで定義したものだけ引いてくるようにしてみました。
ちなみにctorはconstructorの略のようで、調べてみたらちらほら用例があるようです。catみたいな略し方ですね。

comments powered by Disqus