Defining AVERAGING clause
Robert Goldman
rpgoldman at sift.info
Wed Mar 14 22:24:44 UTC 2018
On 14 Mar 2018, at 11:13, Russ Tyndall wrote:
> I think the natural ordering of things means this wont be a problem in
> 99% of situations. Obviously you cant use mean until the finally
> clause, but all of your finally's should come after the averaging
> finally.
Agreed. Still, it's kind of an unhappy feeling to be relying on this
not very user-controlled behavior, and if some day downstream it goes
wrong, that would be problematic.
I guess one would want to be able to build `finally` and `initially`
clauses with `defmacro-clause` where you could specify whether they come
before all end-programmer clauses of the same type, or before all such
clauses of the same type. I suppose one could add sorting to the
`final-code` and `init-code` in `iter`, but that seems fraught with
peril. You're probably right that I should just not worry about this.
>
> (iterate:defmacro-clause (averaging expr &optional into var)
> (let ((avg (or var iterate::*result-var*)))
> (alexandria:with-unique-names (cnt sum)
> `(progn
> (with ,avg)
> (with ,sum = 0)
> (with ,cnt = 0)
> (incf ,cnt)
> (incf ,sum ,expr)
>
> (finally
> (setf ,avg (if (plusp ,cnt) (/ ,sum ,cnt) 0))
> )))))
>
> (iter (for i from 0 to 100)
> (averaging i into mean)
> (finally (return mean)))
> => 50
>
> Expands to:
> (LET* ((I NIL) (MEAN NIL) (#:SUM4008 0) (#:CNT4007 0))
> (BLOCK NIL
> (TAGBODY
> (PROGN (SETQ I -1))
> LOOP-TOP-NIL
> (PROGN
> (SETQ I (+ I 1))
> (IF (> I 100)
> (GO LOOP-END-NIL))
> (PROGN
> (SETQ #:CNT4007 (+ 1 #:CNT4007))
> (SETQ #:SUM4008 (+ I #:SUM4008))))
> (PROGN)
> (GO LOOP-TOP-NIL)
> LOOP-END-NIL
> (PROGN
> (SETF MEAN
> (IF (PLUSP #:CNT4007)
> (/ #:SUM4008 #:CNT4007)
> 0))
> (RETURN MEAN)))
> NIL))
>
> Cheers,
> Russ Tyndall
> Acceleration.net
>
>
> ----- Original Message -----
> From: Robert Goldman [mailto:rpgoldman at sift.info]
> To: russ at acceleration.net
> Cc: iterate-devel at common-lisp.net
> Sent: Tue, 13 Mar 2018 12:27:47 -0500
> Subject: Re: Defining AVERAGING clause
>
> Wouldn't this technique have trouble with code movement issues? For
> example, if I have
> ```
> (iter (for x in data-table)
> (averaging x into mean)
> (finally (return mean)))
> ```
> I know that's a contrived example, but I think the point is clear: if
> I'm going to make `averaging` a collector, I'd like to be able to use
> its result, and if that result is computed in a `finally` block that's
> invisible and out of my control, I can't do it, can I? There's
> `finally-protected`, but I think that's the *opposite* of what I need.
>
> Best,
> r
>
>
> On 13 Mar 2018, at 10:08, Russ Tyndall wrote:
>
>> 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)))))))))
>>
>> Cheers,
>> Russ Tyndall
>> Acceleration.net
>> On 03/13/2018 10:49 AM, Robert Goldman wrote:
>>>
>>> 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
>>>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <https://mailman.common-lisp.net/pipermail/iterate-devel/attachments/20180314/6a2e36a8/attachment.html>
More information about the iterate-devel
mailing list