[iterate-devel] proposed clause (FOR var FROM start BY step LENGTH n)

Tamas K Papp tkpapp at gmail.com
Fri May 1 23:52:33 UTC 2009


Hi everyone,

I would like to propose an additional driver clause, that uses the
syntax

(FOR var FROM start BY step LENGTH n)

One would think that one can substitute for this using

(FOR var FROM start BY step BELOW (+ start (* step n)))

but this has two drawbacks: first, it is inconvenient to use this
calculation every time I want to do this, second, rounding errors can
creep in for floating-point values, eg:

(let* ((n 1000)
       (step pi)
       (n-incorrect
	(iter
	  (for x :from 0 :below (* step n) :by step)
	  (summing 1))))
  (- n n-incorrect))			; gives -1 on my machine

Here is the code I wrote to implement it, but since I am not an expert
on the internals of iterate, it may be improved; or LENGTH could
simply be merged into the current implementation (if that is possible
while still preserving the separate counter).

(defmacro-driver (FOR var FROM start BY step LENGTH n)
  "Iteration starting from start, stepping by step, for a total of n steps."
  ;; Note: reason for this macro is that manual calculation for :below
  ;; (+ start (* step n)) is tedious, and could also lead to incorrect
  ;; number of iterations with floating point values.
  (let ((i (gensym))		  ; counts from 0 to (1- n), inclusive
	(j (gensym))		  ; counts from start, by step
	(kwd (if generate 'generate 'for)))
    `(progn
       (with ,i = 0)
       (with ,j = ,start)
       (,kwd ,var next (prog2 (when (>= ,i ,n) (terminate))
			   ,j
			 (incf ,j ,step)
			 (incf ,i))))))

Examples: 

(iter
  (for i :from 9 :by 2 :length 5)
  (collecting i))                    ; => (9 11 13 15 17)

(iter
  (generate i :from 9 :by 2 :length 5)
  (collecting (next i)))              ; => (9 11 13 15 17)


Can you please include this (or something similar) in the next
release?

Thanks,

Tamas





More information about the iterate-devel mailing list