[plt-scheme] Extending in-vector with start, stop, and step

From: Noel Welsh (noelwelsh at gmail.com)
Date: Tue Jul 15 11:00:24 EDT 2008

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)))


Posted on the users mailing list.