From: Lowell
Subject: Is there a better alternative to this loop idiom?
Date:
Message-ID: <bi4diq$d9b$1@mughi.cs.ubc.ca>
I have a loop which has multiple termination conditions and should
return different values depending on which of the conditions was the
cause of the loop termination. Here is an example (I hope it's clear):
(do (...init...)
((or term1 term2 ...)
(cond (term1 ...)
(term2 ...)
....
So, first I test to see if any of the termination conditions is true,
then use a cond to choose the return value accordingly. This bugs me
because the term[n] forms can be compound forms and significantly
complex. This means that there is duplication of code - the code for
each term[n] appears twice. While this is not inherntly bad, I have a
gut feeling this can be done better, perhaps using a different type of
loop. Any ideas?
Lowell
Lowell wrote:
> So, first I test to see if any of the termination conditions is true,
> then use a cond to choose the return value accordingly. This bugs me
> because the term[n] forms can be compound forms and significantly
> complex. This means that there is duplication of code - the code for
> each term[n] appears twice. While this is not inherntly bad, I have a
> gut feeling this can be done better, perhaps using a different type of
> loop. Any ideas?
Assuming none of the conditions have side effects, this would be equivalent
to
(progn ...init...
(loop
(when term1 (return ...))
(when term2 (return ...))
...))
or
(loop initially ...init... ;;with clauses also, perhaps, after this
doing
(when term1 (return ...))
(when term2 (return ...))
...)
Look at the loop macro in the Hyperspec (Section 6) and I'm sure you'll
figure it out.
faa
> I have a loop which has multiple termination conditions and should
> return different values depending on which of the conditions was the
> cause of the loop termination. [...]
>
> (do (...init...)
> ((or term1 term2 ...)
> (cond (term1 ...)
> (term2 ...)
> ....
How about:
(do (...init...)
((cond (term1 ... (return ...))
(term2 ... (return ...))
...
(t nil) ; No term was applicable - drop through
))
...)
This is only a minor abuse of the usual semantics of the end-test
clause - I think the meaning is clear enough.
-nick
From: Frode Vatvedt Fjeld
Subject: Re: Is there a better alternative to this loop idiom?
Date:
Message-ID: <2hisoqrrs6.fsf@vserver.cs.uit.no>
Lowell <······@cs.ubc.ca> writes:
> (do (...init...)
> ((or term1 term2 ...)
> (cond (term1 ...)
> (term2 ...)
> ....
>
> [..] Any ideas?
If for some reason you don't want to use loop, do something like this:
(do (...init...)
()
(when term1 (return ..))
(when term2 (return ..))
...)
Many times, one of the exit conditions will be the "natural" one
(term0 below), in which case I think it's good style to say:
(do (...init...)
(term0 ..)
(when term1 (return ..))
(when term2 (return ..))
...)
--
Frode Vatvedt Fjeld
Lowell <······@cs.ubc.ca> writes:
> I have a loop which has multiple termination conditions and should
> return different values depending on which of the conditions was the
> cause of the loop termination. Here is an example (I hope it's clear):
>
> (do (...init...)
> ((or term1 term2 ...)
> (cond (term1 ...)
> (term2 ...)
> ....
>
> So, first I test to see if any of the termination conditions is true,
> then use a cond to choose the return value accordingly. This bugs me
> because the term[n] forms can be compound forms and significantly
> complex. This means that there is duplication of code - the code for
> each term[n] appears twice. While this is not inherntly bad, I have a
> gut feeling this can be done better, perhaps using a different type of
> loop. Any ideas?
Idiom? Then Macro!
(defmacro mydo (inits terms-res &body body)
"terms-res is like: (term1 . res1) (term2 . res2) ... (termN . resN)"
(let ((terms (mapcar (lambda (x) (gensym "TERM")) terms-res)))
`(do ,(append inits (mapcar (lambda (x) (list x nil)) terms))
((or ,@(mapcan (lambda (var expr) `((setq ,var ,expr)))
terms (mapcar (function car) terms-res)))
(cond
,@(mapcar (lambda (var res) `(,var ,@res))
terms (mapcar (function cdr) terms-res))))
,@body)))
[35]> (macroexpand-1 '(mydo ((a 0) (b 1))
(((complex-1) (compute-res1) res1)
((complex-2) (compute-res2) res2)
((complex-3) res3))
(statements)))
(DO ((A 0) (B 1) (#:TERM669 NIL) (#:TERM670 NIL) (#:TERM671 NIL))
((OR (SETQ #:TERM669 (COMPLEX-1)) (SETQ #:TERM670 (COMPLEX-2))
(SETQ #:TERM671 (COMPLEX-3)))
(COND (#:TERM669 (COMPUTE-RES1) RES1) (#:TERM670 (COMPUTE-RES2) RES2)
(#:TERM671 RES3)))
(STATEMENTS)) ;
T
--
__Pascal_Bourguignon__ http://www.informatimago.com/
----------------------------------------------------------------------
Do not adjust your mind, there is a fault in reality.
From: Thomas A. Russ
Subject: Re: Is there a better alternative to this loop idiom?
Date:
Message-ID: <ymismntl76s.fsf@sevak.isi.edu>
Lowell <······@cs.ubc.ca> writes:
> I have a loop which has multiple termination conditions and should
> return different values depending on which of the conditions was the
> cause of the loop termination. Here is an example (I hope it's clear):
>
> (do (...init...)
> ((or term1 term2 ...)
> (cond (term1 ...)
> (term2 ...)
> ....
>
> So, first I test to see if any of the termination conditions is true,
> then use a cond to choose the return value accordingly. This bugs me
> because the term[n] forms can be compound forms and significantly
> complex. This means that there is duplication of code - the code for
> each term[n] appears twice. While this is not inherntly bad, I have a
> gut feeling this can be done better, perhaps using a different type of
> loop. Any ideas?
A couple of ideas:
#1. If you can guarantee that the return values are always non-NIL,
then you can use the cond itself as the termination test:
(do (...init...)
((cond (term1 ...)
(term2 ...)
....
(t NIL)))
...)
#2. A bit safer, since this doesn't depend on the return value:
(block fancy-loop
(do (...init...)
((cond (term1 (return-from fancy-loop ...))
(term2 (return-from fancy-loop ...))
....
(t NIL)))
...))
#3. Using the loop construct:
(loop initially (...init...)
...other loop iteration clauses...
when term1 return res1
when term2 return res2
...
do ... body ...)
You can choose to place the body either before or after the
termination clause test.
--
Thomas A. Russ, USC/Information Sciences Institute
Thomas A. Russ wrote:
> Lowell <······@cs.ubc.ca> writes:
> #3. Using the loop construct:
>
> (loop initially (...init...)
> ...other loop iteration clauses...
> when term1 return res1
> when term2 return res2
> ...
> do ... body ...)
>
> You can choose to place the body either before or after the
> termination clause test.
I think the following is what the OP actually wants:
(loop initially (... init ...)
...
when term1 return it
when term2 return it
...
do ...)
This ensures that the possible result terms are evaluated exactly once
per iteration. "it" refers to the result of the test expression for the
respective when.
Pascal
From: Lowell
Subject: Re: Is there a better alternative to this loop idiom?
Date:
Message-ID: <bi6aoe$mpa$1@mughi.cs.ubc.ca>
Actually not. What to return depends on which termination condition is
satisified, but what is actually returned is not the value of the
condition itself. However, your example is interesting becasue I didn't
know about using 'it' in loops.
Lowell
Pascal Costanza wrote:
> I think the following is what the OP actually wants:
>
> (loop initially (... init ...)
> ...
> when term1 return it
> when term2 return it
> ...
> do ...)
>
> This ensures that the possible result terms are evaluated exactly once
> per iteration. "it" refers to the result of the test expression for the
> respective when.
>
>
> Pascal
>
Lowell wrote:
> Actually not. What to return depends on which termination condition is
> satisified, but what is actually returned is not the value of the
> condition itself. However, your example is interesting becasue I didn't
> know about using 'it' in loops.
Ah, ok, then I misunderstood you...
Pascal