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