Hello,
Ports and lists are "iterable". Vectors, strings, and bytevectors are
"mutable indexable".
Import my 'define-record-type++':
(import (dharmalab records define-record-type))
Define the "iterable" protocol:
(define-record-type++ iterable-protocol
(fields iterator empty? next rest new-from-list))
Define 'for-each' functor over the iterable protocol:
(define (make-iterable-for-each protocol)
(import-iterable-protocol protocol)
(define (for-each col f)
(let loop ((iter (iterator col)))
(when (not (empty? iter))
(f (next iter))
(loop (rest iter)))))
for-each)
Define the iterable protocol for lists:
(define iterable-protocol/list
(make-iterable-protocol (lambda (x) x)
null?
car
cdr
(lambda (x) x)))
Define list-for-each:
(define list-for-each
(make-iterable-for-each iterable-protocol/list))
Define the iterable protocol for input-ports:
(define iterable-protocol/input-port
(make-iterable-protocol (lambda (x) x)
(lambda (p)
(eof-object?
(lookahead-char p)))
lookahead-char
(lambda (p)
(get-char p)
p)
#f))
Define input-port-for-each:
(define input-port-for-each
(make-iterable-for-each iterable-protocol/input-port))
Now let's switch over to the mutable indexable protocol.
Define it:
(define-record-type++ mutable-indexable-protocol
(fields new-of-length size ref put copy))
Define the 'for-each' functor over the mutable-indexable protocol:
(define (make-mutable-indexable-for-each protocol)
(import-mutable-indexable-protocol protocol)
(define (for-each seq proc)
(let ((n (size seq)))
(let loop ((i 0))
(when (< i n)
(proc (ref seq i))
(loop (+ i 1))))))
for-each)
Define the mutable-indexable-protocol for vectors:
(define mutable-indexable-protocol/vector
(make-mutable-indexable-protocol make-vector
vector-length
vector-ref
vector-set!
vector-copy-into!
))
Define vector-for-each:
(define vector-for-each
(make-mutable-indexable-for-each mutable-indexable-protocol/vector))
Define the mutable-indexable-protocol for strings:
(define mutable-indexable-protocol/string
(make-mutable-indexable-protocol make-string
string-length
string-ref
string-set!
string-copy-into!
))
Define string-for-each:
(define string-for-each
(make-mutable-indexable-for-each mutable-indexable-protocol/string))
Similar for bytevectors.
The benefit is that you define 'for-each' once for each protocol and all
implementors of the protocol get it "for free".
If anybody knows of previous work in this area for Scheme, let me know.
Also, I'd like to hear folks's opinion on this issue...
It's possible to have vectors be "iterable" by having an iterator
interface over them. One drawback is that the iterator abstraction adds
some overhead; there is no layer of abstraction involved with the
"mutable indexable" protocol. If performance is a priority, a separate
protocol seems the way to go.
Ed