[plt-scheme] Extending in-vector with start, stop, and step
Hi all,
I've extended in-vector to handle start, stop, and step parameters, in
line with in-range. Prototype implementation below (it needs more
error checking, and doesn't work when used outside comprehensions;
otherwise it passes all my tests). Is there any interest in adding
this to the core of PLT Scheme? I've also defined for/vector,
for/vector/fold, and in-vector-reverse (though these don't collide
with PLT built-ins, so I'm happier to use them standalone).
Cheers,
Noel
Implementation, named ein-vector to avoid name collision:
(define-for-syntax (:ein-vector stx)
(syntax-case stx ()
[((x) (ein-vector v))
(:ein-vector
(syntax ((x) (ein-vector v 0 #f 1))))]
[((x) (ein-vector v start))
(:ein-vector
(syntax ((x) (ein-vector v start #f 1))))]
[((x) (ein-vector v start stop))
(:ein-vector
(syntax ((x) (ein-vector v start stop 1))))]
[((x) (ein-vector v start stop step))
#'[(x)
(:do-in
;; Outer bindings
;; Prevent multiple evaluation
([(v* stop*) (let ([vec v]
[stop* stop])
(if stop*
(values vec stop*)
(values vec (vector-length vec))))]
[(start*) start]
[(step*) step])
;; Outer check
;; TODO: Raise exception on failure
(let ([length (vector-length v*)])
(and (>= start* 0)
(<= start* stop*)
(<= stop* length)
(> step* 0)))
;; Loop bindings
([idx start*])
;; Pos guard
(< idx stop*)
;; Inner bindings
([(x) (vector-ref v* idx)])
;; Pre guard
#t
;; Post guard
#t
;; Loop args
((+ idx step)))]]))
(define-sequence-syntax ein-vector
;; TODO: Extend to handle use outside comprehensions
(lambda () #'in-vector)
:ein-vector)
Tests:
(test-case
"in-vector"
(check-equal?
(for/list ([v (in-vector #(1 2 3 4))])
v)
'(1 2 3 4)))
(test-case
"in-vector w/ start"
(check-equal?
(for/list ([v (ein-vector #(1 2 3 4) 1)])
v)
'(2 3 4)))
(test-case
"in-vector w/ start & stop"
(check-equal?
(for/list ([v (ein-vector #(1 2 3 4 5) 1 4)])
v)
'(2 3 4)))
(test-case
"in-vector w/ start & stop & step"
(check-equal?
(for/list ([v (ein-vector #(0 1 2 3 4 5 6 7) 1 5 2)])
v)
'(1 3)))
(test-case
"in-vector evaluates vector once"
(let ([count 0])
(check-equal?
(for/list ([v (ein-vector (begin (set! count (add1 count)) #(1 2 3)))])
v)
'(1 2 3))
(check-equal? count 1)))