From: Rusty Shackleford
Subject: need help with looping
Date: 
Message-ID: <slrnd16jah.2fj.rs@mwilson.umlcoop.net>
I've read several websites but I still don't understand how to write a
kind of loop in lisp.

Here's what I want to do, expressed in C:

int x = 0;
while (x != 99) x = foo();

In lisp, I tried

(loop for x = 0 until (eql x 99)
    do (setf x (foo)))

But that caused an infinite loop.  I'm guessing the x I bound to in the
setf is not the x used in the top line.

Anyway, any help with this would really be appreciated.

TIA

From: Ed Symanzik
Subject: Re: need help with looping
Date: 
Message-ID: <cv02vt$rmq$1@msunews.cl.msu.edu>
Rusty Shackleford wrote:
> I've read several websites but I still don't understand how to write a
> kind of loop in lisp.
> 
> Here's what I want to do, expressed in C:
> 
> int x = 0;
> while (x != 99) x = foo();
> 
> In lisp, I tried
> 
> (loop for x = 0 until (eql x 99)
>     do (setf x (foo)))
> 
> But that caused an infinite loop.  I'm guessing the x I bound to in the
> setf is not the x used in the top line.
> 
> Anyway, any help with this would really be appreciated.
> 
> TIA

Well, since x doesn't appear to be global, foo() has no access to or 
need for it.  If the code following the loop needs it, the value is 
known to be 99.  Also, x is defined to be an integer, so we can use =.

(loop until (= (foo) 99))

However, the return value doesn't always have to be the same type.  With 
C, you define foo() to return an int, but with Lisp you could return NIL 
to flag the end condition, and meaningful integers otherwise.  (you can 
also multiple return values, but I'll skip that)  Anything non-NIL is 
"true", so:

(loop while (foo))
From: Wade Humeniuk
Subject: Re: need help with looping
Date: 
Message-ID: <s9IQd.59421$gA4.20884@edtnps89>
Rusty Shackleford wrote:

> 
> (loop for x = 0 until (eql x 99)
>     do (setf x (foo)))
> 
> But that caused an infinite loop.  I'm guessing the x I bound to in the
> setf is not the x used in the top line.
> 

replace FOR with WITH

(loop with x = 0 until (eql x 99)
     do (setf x (foo)))

using FOR means x is reassigned 0 everytime through the loop.

Wade
From: Rusty Shackleford
Subject: Re: need help with looping
Date: 
Message-ID: <slrnd16jri.2ts.rs@mwilson.umlcoop.net>
On Wed 16 Feb 2005 08:47:04 AM EST, Wade Humeniuk wrote:
> replace FOR with WITH
>
> (loop with x = 0 until (eql x 99)
>      do (setf x (foo)))
>
> using FOR means x is reassigned 0 everytime through the loop.
>
> Wade


Thanks a lot!
From: Trent Buck
Subject: Re: need help with looping
Date: 
Message-ID: <20050217005310.196a196b@harpo.marx>
Up spake Rusty Shackleford:
> I've read several websites but I still don't understand how to write a
> kind of loop in lisp.
> 
> Here's what I want to do, expressed in C:
> 
> int x = 0;
> while (x != 99) x = foo();

	(do ((x 0 (foo)))
            (= x 99))

Don't try to use LOOP (or even DO?) on your first try.  Try to munge the
iteration to use DOTIMES or DOLIST.  If you like SICP-style, you could
make it a tail recursion:

	(labels ((recurse (x)
                    (if (not (= x 99))
                        (recurse (foo)))))
          (recurse (foo)))

> But that caused an infinite loop.  I'm guessing the x I bound to in the
> setf is not the x used in the top line.

Dunno.  I haven't tried to understand LOOP yet :-)

-- 
-trent
Is it so difficult to master your bloody pride and admit that yes, a bunch
of hackers turned out a better suite of utilities than your teams of
engineers ever could?
 -- Robert Uhl
From: Matthieu Villeneuve
Subject: Re: need help with looping
Date: 
Message-ID: <42138473$0$18648$626a14ce@news.free.fr>
"Trent Buck" <·········@tznvy.pbz> wrote in message
····························@harpo.marx...
> Up spake Rusty Shackleford:
> > I've read several websites but I still don't understand how to write a
> > kind of loop in lisp.
> >
> > Here's what I want to do, expressed in C:
> >
> > int x = 0;
> > while (x != 99) x = foo();
>
> (do ((x 0 (foo)))
>             (= x 99))
>
> Don't try to use LOOP (or even DO?) on your first try.  Try to munge
> the iteration to use DOTIMES or DOLIST.

Why? Code using LOOP is often much simpler and more explicit than
the equivalent using DO, especially with more complex iterations.
And LOOP really isn't that difficult to learn/use...

> If you like SICP-style, you could
> make it a tail recursion:
>
> (labels ((recurse (x)
>                     (if (not (= x 99))
>                         (recurse (foo)))))
>           (recurse (foo)))

That's even worse... :)


--
Matthieu Villeneuve
From: Trent Buck
Subject: Re: need help with looping
Date: 
Message-ID: <20050217055518.54cba525@harpo.marx>
Up spake Matthieu Villeneuve:
> > Don't try to use LOOP (or even DO?) on your first try.  Try to munge
> > the iteration to use DOTIMES or DOLIST.
> 
> Code using LOOP is often much simpler and more explicit than
> the equivalent using DO, especially with more complex iterations.

Yes, well.  For complicated loops, LOOP may be a good idea, but how
often will newbies require lists that complicated?  For simple loops, I
prefer DO / DOTIMES / DOLIST.  LOOP feels like sh's "for i in STRING*;
do BLOCK; done".

> And LOOP really isn't that difficult to learn/use...

Well *I* can't grok it by looking at the BNF in the hyperspec :-)

-- 
-trent
Unix doesn't prevent you from doing something stupid because
that would prevent me from doing something clever.
From: Edi Weitz
Subject: Re: need help with looping
Date: 
Message-ID: <u3bvw7gvb.fsf@agharta.de>
On Wed, 16 Feb 2005 13:40:33 GMT, Rusty Shackleford <··@natchie.mine.nu> wrote:

> In lisp, I tried
>
> (loop for x = 0 until (eql x 99)
>     do (setf x (foo)))
>
> But that caused an infinite loop.  I'm guessing the x I bound to in
> the setf is not the x used in the top line.

It's the same X but it's reset to 0 on each loop because of the FOR.
What you want (I guess) is either

  (loop with x = 0
        until (eql x 99)
        do (setf x (foo)))

or

  (let ((x 0))
    (loop until (eql x 99)
          do (setf x (foo))))

or

  (loop for x = 0 then (foo)
        until (eql x 99))

I think the third form is the most elegant one but YMMV.

See <http://www.gigamonkeys.com/book/loop-for-black-belts.html> - or
did you read that already?

Cheers,
Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Thomas A. Russ
Subject: Re: need help with looping
Date: 
Message-ID: <ymiis4s1c2d.fsf@sevak.isi.edu>
Edi Weitz <········@agharta.de> writes:

> It's the same X but it's reset to 0 on each loop because of the FOR.
> What you want (I guess) is either
> 
>   (loop with x = 0
>         until (eql x 99)
>         do (setf x (foo)))
> 
> or
> 
>   (let ((x 0))
>     (loop until (eql x 99)
>           do (setf x (foo))))
> 
> or
> 
>   (loop for x = 0 then (foo)
>         until (eql x 99))

or even shorter:

    (loop for x = (foo)
          until (eql x 99))


-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Edi Weitz
Subject: Re: need help with looping
Date: 
Message-ID: <ubrak43rp.fsf@agharta.de>
On 16 Feb 2005 12:31:38 -0800, ···@sevak.isi.edu (Thomas A. Russ) wrote:

> or even shorter:
>
>     (loop for x = (foo)
>           until (eql x 99))

This will also break if X is special, see my reply to Wade.

Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Thomas A. Russ
Subject: Re: need help with looping
Date: 
Message-ID: <ymihdkb15w6.fsf@sevak.isi.edu>
Edi Weitz <········@agharta.de> writes:

> 
> On 16 Feb 2005 12:31:38 -0800, ···@sevak.isi.edu (Thomas A. Russ) wrote:
> 
> > or even shorter:
> >
> >     (loop for x = (foo)
> >           until (eql x 99))
> 
> This will also break if X is special, see my reply to Wade.

OK.  Found it.
That is just perverse :) and deserves to infinite loop.

Besides, "x" can't be special, it doesn't have "*" around its name.
(just kidding).

In the case of having to deal with side effects, one should want to code
even more defensively, and use (>= x 99) instead of (eql x 99) as the
termination test.  I mean, what if foo were defined as

(defun foo () (incf x 2))

-- 
Thomas A. Russ,  USC/Information Sciences Institute
From: Wade Humeniuk
Subject: Re: need help with looping
Date: 
Message-ID: <KiIQd.59493$gA4.21549@edtnps89>
Edi Weitz wrote:

> 
>   (loop for x = 0 then (foo)
>         until (eql x 99))
> 

(loop until (eql (foo) 99))

Wade
From: Edi Weitz
Subject: Re: need help with looping
Date: 
Message-ID: <uy8do61mg.fsf@agharta.de>
On Wed, 16 Feb 2005 13:56:58 GMT, Wade Humeniuk <··················@telus.net> wrote:

> (loop until (eql (foo) 99))

without initializing X?

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Wade Humeniuk
Subject: Re: need help with looping
Date: 
Message-ID: <HJIQd.59698$gA4.12647@edtnps89>
Edi Weitz wrote:
> On Wed, 16 Feb 2005 13:56:58 GMT, Wade Humeniuk <··················@telus.net> wrote:
> 
> 
>>(loop until (eql (foo) 99))
> 
> 
> without initializing X?
> 

There is no X. :)

Wade
From: Edi Weitz
Subject: Re: need help with looping
Date: 
Message-ID: <uu0oc605s.fsf@agharta.de>
On Wed, 16 Feb 2005 14:25:43 GMT, Wade Humeniuk <··················@telus.net> wrote:

> There is no X. :)


  * (defparameter x 100)

  X
  * (defun foo () (incf x))

  FOO
  * (loop for x = 0 then (foo) until (eql x 99))

  NIL
  * (loop until (eql (foo) 99))

  ;;; endless loop here...


Yeah, I know that's bad style... :)

Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Peder O. Klingenberg
Subject: Re: need help with looping
Date: 
Message-ID: <kswtt8vceu.fsf@beto.netfonds.no>
Rusty Shackleford <··@natchie.mine.nu> writes:

> (loop for x = 0 until (eql x 99)
>     do (setf x (foo)))
>
> But that caused an infinite loop.  I'm guessing the x I bound to in the
> setf is not the x used in the top line.

Yes, they're the same x, but when you use "for-as-equals" without a
clause specifying subsequent values of x, x will be initialized to 0
on every iteration.

Try this instead:
(loop for x = 0 then (setf x (foo))
      until (eql x 99))

Add a "finally return x" after the until-clause to have the loop
return something other than nil.

See the hyperspec section 6.1.2.1.4

...Peder...
-- 
I wish a new life awaited _me_ in some off-world colony.
From: Louis Theran
Subject: Re: need help with looping
Date: 
Message-ID: <42152aad_1@rcfnews.cs.umass.edu>
On 2005-02-16 08:40:33 -0500, Rusty Shackleford <··@natchie.mine.nu> said:

> Here's what I want to do, expressed in C:
> 
> int x = 0;
> while (x != 99) x = foo();

Assuming that you don't know that x is 99 when the loop ends, and you 
want the value, you can use something like this.

(loop for x = 0 then (foo)
      until (= x 99)
      finally (return x))

If you just want to call foo repeatedly until it returns 99, then use this.

(loop until (= 99 (foo)))

^L
From: Surendra Singhi
Subject: Re: need help with looping
Date: 
Message-ID: <cv5ppv$dkk$1@news.asu.edu>
Rusty Shackleford wrote:
> I've read several websites but I still don't understand how to write a
> kind of loop in lisp.
> 
> Here's what I want to do, expressed in C:
> 
> int x = 0;
> while (x != 99) x = foo();
> 
> In lisp, I tried
> 
> (loop for x = 0 until (eql x 99)
>     do (setf x (foo)))
> 
> But that caused an infinite loop.  I'm guessing the x I bound to in the
> setf is not the x used in the top line.
> 
A good tool to have in one's repertoire is "macroexpand" because it will 
help you understand how your "loop" might be getting expanded

For example with your code it expands as:

CL-USER> (macroexpand-1 '(loop for x = 0 until (eql x 99)
     do (setf x (foo))))
(MACROLET ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-ERROR)))
  (BLOCK NIL
   (LET ((X 0))
    (LET NIL
     (MACROLET ((LOOP-FINISH NIL '(GO SYSTEM::END-LOOP)))
      (TAGBODY SYSTEM::BEGIN-LOOP
       (PROGN (WHEN (EQL X 99) (LOOP-FINISH)) (PROGN (SETF X (FOO))))
       (PSETQ X 0) (GO SYSTEM::BEGIN-LOOP) SYSTEM::END-LOOP
       (MACROLET
        ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-WARN)
          '(GO SYSTEM::END-LOOP))))))))))
T


Notice the (PSETQ X 0) between the begin-loop and end-loop, and that was 
the cause of your problem.

And now look at Wade's solution

CL-USER> (macroexpand '(loop with x = 0 until (eql x 99)
     do (setf x (foo))) )
(MACROLET ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-ERROR)))
  (BLOCK NIL
   (LET ((X 0))
    (LET NIL
     (MACROLET ((LOOP-FINISH NIL '(GO SYSTEM::END-LOOP)))
      (TAGBODY SYSTEM::BEGIN-LOOP
       (PROGN (WHEN (EQL X 99) (LOOP-FINISH)) (PROGN (SETF X (FOO))))
       (GO SYSTEM::BEGIN-LOOP) SYSTEM::END-LOOP
       (MACROLET
        ((LOOP-FINISH NIL (SYSTEM::LOOP-FINISH-WARN)
          '(GO SYSTEM::END-LOOP))))))))))
T


HTH
-- 
Surendra Singhi

www.public.asu.edu/~sksinghi/