call-with-iteratorがよくわからない
何故こういう仕様なのか?どこに疑問を持ったかというと,コールバックに渡される二つの関数が,「無引数で何度も呼び出され,違う値を返すことを期待される」こと.つまり副作用必至なのだ.多分.
どうせなら関数的に書きたいよね.
というわけで,副作用無しで書けるインタフェースを考えてみた.
(define-method call-with-iterator* ((lis <list>) iteratee . args) (iteratee null? car cdr lis)) (define-method call-with-iterator* ((vec <vector>) iteratee . args) (iteratee (lambda (i) (>= i (vector-length vec))) (pa$ vector-ref vec) (pa$ + 1) 0)) (define (my-map proc coll) (define (func p f g seed) (let loop ((seed seed) (lis '())) (if (p seed) (reverse lis) (loop (g seed) (cons (proc (f seed)) lis))))) (call-with-iterator* coll func)) (my-map (pa$ + 1) '(1 2 3)) ; => (2 3 4) (my-map (pa$ + 1) '#(1 2 3)) ; => (2 3 4)
unfold臭がするのは何故だろう?キーワード引数startはとりあえず考えてない.
元のcall-with-iteratorからすると,結局あちこちに引数が増えただけなので,そういう意味では実装可能だと思う.パフォーマンス的なところはよくわからない.いざとなれば各メソッドを直接定義しちゃう手段があるからこのくらいは問題にならない気がするけど,という素人意見.
個人的には,このcall-with-iterator*を使って元のcall-with-iteratorが定義できれば満足なのかな.
(use gauche.collection) (define-class <foo> (<collection>) ()) (define-method call-with-iterator* ((foo <foo>) iteratee . args) (iteratee null? car cdr '(1 2 3))) (define-method call-with-iterator ((foo <foo>) iteratee . args) (call-with-iterator* foo (lambda (p f g seed) (define val seed) (iteratee (lambda () (p val)) (lambda () (begin0 (f val) (set! val (g val)))))))) (map (pa$ + 1) (make <foo>)) ; => (2 3 4)
これでできてるのかな?
(lambda () (p val))
のところを,最初(pa$ p val)
って書いててはまった.副作用があると意味が変わる.ああ,副作用怖い.