#:g1: SBCL: Extensible Sequencesの紹介

Posted 2014-12-06 15:00:00 GMT

(LISP Library 365参加エントリ)

 LISP Library 365 の341日目です。

SBCL: Extensible Sequencesとはなにか

 SBCL: Extensible Sequencesは、

パッケージ情報

パッケージ名SBCL: Extensible Sequences
ドキュメントSBCL User Manual: Extensible Sequences

インストール方法

 SBCLの標準機能で、sb-sequence(sequence)パッケージで定義されています。

試してみる

 ANSI Common Lispでは色々あってユーザー定義のsequenceのサブクラスは一連のsequence関数では使えないのですが、ANSI準拠に篤いSBCLにしては珍しく仕様を拡張してユーザー定義のsequenceを許すという拡張機能です。

 sb-sequence(sequence)で提供されているメソッド群ですが、ざっと

という感じです。
Common Lisp標準のsequence関数と同名のものが多いですが、sequence:fooの方で拡張を作ると、cl:fooの方でもユーザー拡張のクラスが使えるようになります。

 この拡張案については、CDRでも提案されていますが、内容/経緯についてはこのCDRに詳しいです。

 では、試しに例として、適当にseriesと合体させてみます。

(defmethod sequence:emptyp ((seq foundation-series))
  (zerop (series:collect-length (series:subseries seq 0 1))))

(sequence:emptyp (series:scan '())) ;=> T

(defmethod sequence:make-sequence-like ((seq foundation-series) length &key initial-element initial-contents) (cond ((= length 0) (series:scan nil)) (initial-contents (series:scan initial-contents)) (t (series:mapping ((i (series:scan-range :from 0 :below length)) (e (series:series initial-element))) e))))

(coerce '(1 2 3 4 5) 'foundation-series) ;=> #Z(1 2 3 4 5)

(sequence:make-sequence-like (series:scan '()) 8 :initial-element 'z) ;=> #Z(Z Z Z Z Z Z Z Z)

(make-sequence 'foundation-series 4 :initial-element 42) ;=> #Z(42 42 42 42)

(defmethod sequence:adjust-sequence ((seq foundation-series) length &key initial-element (initial-contents nil ic-sp)) (cond ((= length 0) (series:scan nil)) (ic-sp (series:subseries (series:catenate seq (series:scan initial-contents)) 0 length)) (T (series:subseries (series:catenate seq (series:series initial-element)) 0 length))))

(sequence:adjust-sequence (series:scan-range :from 0 :upto 10) 15) ;=> #Z(0 1 2 3 4 5 6 7 8 9 10 NIL NIL NIL NIL)

(defmethod sequence:elt ((seq foundation-series) index) (series:collect-nth index seq))

(elt (series:scan-range :from 0 :upto 10) 9) ;=> 9

(defmethod sequence:subseq ((seq foundation-series) start &optional end) (if end (series:subseries seq start end) (series:subseries seq start)))

(subseq (series:scan-range :from 0 :upto 10) 5) ;=> #Z(5 6 7 8 9 10)

(defmethod sequence:length ((seq foundation-series)) (series:collect-length seq))

(length (series:scan-range :from 0 :upto 10)) ;=> 11

 という風に数点メソッドを書いてみましたが、それだけでも面白いです。
ちなみに思い付きで始めてしまいましたが、seriesは構造体で定義されているので、上記のように書くには構造体からクラスに変更する必要があり、さらにseriesのマクロの式変形黒魔術による最適化は一切考慮されていないので、使い物には全然ならないという例になりました…。

 ざっとQuicklispを眺めてみると、dlist、projectured、sequence-iteratorsあたりで使われているようですので、拡張を書いてみたい場合は、これらを参考にすると良いかなと思います。

まとめ

 今回は、SBCL: Extensible Sequencesを紹介してみました。
結構前から実装されていた機能なのですがドキュメント化されたのはここ1、2年だったと思います。
処理系依存ではありますが便利な機能ではあります。

comments powered by Disqus