Here is an existing "sampling" clause to pull a random sample from a larger data set. The long and short is just use a finally clause, as you would when writing a normal iterate loop.
(iterate:defmacro-clause (sampling expr &optional into var
size size)
"resevoir sample the input"
(let ((sample (or var iterate::*result-var*)))
(alexandria:with-unique-names (i sample-size sigil buffer row)
`(progn
(with ,sample)
(with ,sample-size = (or ,size 100))
(with ,buffer = (make-array ,sample-size :initial-element
',sigil))
(with ,i = 0)
(if (< ,i ,sample-size)
(setf (aref ,buffer ,i) ,expr)
(let ((r (random ,i)))
(when (< r ,sample-size)
(setf (aref ,buffer r) ,expr))))
(incf ,i)
(finally
;; convert our sample to a list, but only if we actually
took the sample
(when (plusp ,i)
(setf ,sample
(iter (for ,row in-vector ,buffer)
(until (eq ,row ',sigil))
(collect ,row)))))))))
I was going to define an
AVERAGING
collector clause for iterate, but I'm not sure how to do it. The obvious thing, it seemed to me, would be to sum the values as I go along, and count them, and then divide the sum by the count when leaving the loop.But the examples for
DEFMACRO-CLAUSE
in the manual do all of their work while iterating, and there doesn't seem to be an "at-end" hook. Is the kind of thing I would like feasible, and if so, how is it to be done?thanks!
r