のゼロ元オブジェクトを作ってみた
(use gauche.collection) (use gauche.mop.singleton) (define-class <zero-collection-meta> (<singleton-meta>) ()) (define-class <zero-collection> (<collection>) () :metaclass <zero-collection-meta>) (define-method call-with-iterator ((class <zero-collection>) proc :key start) (proc (^ () #t) (^ () (error "zero-collection has no element")))) (define-method call-with-builder ((class <zero-collection-meta>) proc :key size) (unless (or (undefined? size) (zero? size)) (error "wrong size" size)) (proc (^_ (error "cannot add element to zero-collection")) (cut instance-of <zero-collection>)))
これがあれば,結果の要素の型が引数の型になるジェネリックな append
が書けるんじゃないのか?書いてみた.
(define-method empty? ((coll <collection>)) (= 0 (size-of coll))) (define-method first ((coll <collection>)) (with-iterator (coll end? next) (if (end?) (error "no element" coll) (next))))
(define-method concat-to ((class <class>) (coll <collection>)) (with-builder (class add! get) (for-each (cut for-each add! <>) coll) (get))) (define-method concat ((coll <collection>)) (if-let1 it (find ($ not $ (cut is-a? <> <zero-collection>) $) coll) (concat-to (class-of it) coll) (instance-of <zero-collection>))) (define-method ++-to ((class <class>) :rest args) (concat-to class args)) (define-method ++ (:rest args) (concat args))
例:
(++) ; => #<<zero-collection> 0xe711d8> (++ "foo" (++) "bar") ; => "foobar" (++ (++) "foo") ; => "foo"
これってモノイドなのかな.<collection>
として定義してあるけど,もっと一般的に定義できるかもしれない.より一般的に定義したとして,おいしくなるかどうかは分からないけれど.