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

From: Frank A. Adrian
Subject: Re: Is there a better alternative to this loop idiom?
Date: 
Message-ID: <bmj1b.120$OK2.129985@news.uswest.net>
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
From: Nick Levine
Subject: Re: Is there a better alternative to this loop idiom?
Date: 
Message-ID: <8732fc48.0308220344.3d580307@posting.google.com>
> 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
From: Pascal Bourguignon
Subject: Re: Is there a better alternative to this loop idiom?
Date: 
Message-ID: <87ekzd7vrp.fsf@thalassa.informatimago.com>
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
From: Pascal Costanza
Subject: Re: Is there a better alternative to this loop idiom?
Date: 
Message-ID: <bi684p$19j$1@newsreader2.netcologne.de>
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
> 
From: Pascal Costanza
Subject: Re: Is there a better alternative to this loop idiom?
Date: 
Message-ID: <bi6du4$b4h$1@newsreader2.netcologne.de>
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