From: Nir Sullam
Subject: Simple LOOP question
Date: 
Message-ID: <7jai08$7a7$1@lnews.actcom.co.il>
In AutoLISP I am used to loop with while until I press Enter :

(while
  (getname) ; read string function
  (add to list) ; add to a list function
)


How can I do it in CL simply and without to much code ??

The CLTL is detailed but seems not to have that answer easy to find, the
loop function seems too much for the task.



TIA

Nir

From: Graham Hughes
Subject: Re: Simple LOOP question
Date: 
Message-ID: <87k8tjc9xk.fsf@oak.treepeople.net>
>>>>> "Nir" == Nir Sullam <······@actcom.co.il> writes:

    Nir> In AutoLISP I am used to loop with while until I press Enter :
    Nir> (while (getname) ; read string function (add to list) ; add to
    Nir> a list function )

Well, one way is
	(loop (setq text (getname))
	      (if (null text) ...)
	      ...)

but this is not particularly functional. (Although bare loop is useful
from time to time.)

You could also do
	(do ((text (getname) (getname)))
	    ((null text) ...returned-value...)
	  ...body...)

Or

	(loop for text = (getname) then (getname)
	      while text
                do ...)

However, since this is CL you can simply define a while loop like so: 

(defmacro while (test &body body)
  `(do ()
       ((not ,test))
     ,@body))

(which is due to Paul Graham) and then you can just use

(while (setq text (gettext))
  (operate-on text))

as you're used to doing in Autolisp.
-- 
Graham Hughes <·······@cs.ucsb.edu>
PGP Fingerprint: 36 15 AD 83 6D 2F D8 DE  EC 87 86 8A A2 79 E7 E6
((lambda (x) (list x (list 'quote x)))
 '(lambda (x) (list x (list 'quote x))))
From: Kent M Pitman
Subject: Re: Simple LOOP question
Date: 
Message-ID: <sfwiu92ahh3.fsf@world.std.com>
Graham Hughes <·······@cs.ucsb.edu> writes:

>       (loop for text = (getname) then (getname)
>             while text
>               do ...)

FYI, if the "then" thing is the same, I don't think you need to repeat it.
The "form2" defaults to the "form1" in the "foo = form1 then form2" syntax.
See 6.1.2.1.4 in CLHS.  So:

|| (loop for text = (getname)
||       while text 
||       do ...)

Of course, one can also write (and I often do)

|| (loop (let ((text (getname)))
||         (unless text (return))
||         ...))

 - - - - - - - - - - - - - - - - - -
[EXTREMELY MINOR STYLE POINT FOLLOWS]

Incidentally, regarding the loop up at top, I personally don't recommend
indenting the do.  It doesn't matter to the meaning, of course, but in
the style rules I encourage, indented terms usually mean they are
conditional or substructure to the one above them.  For example,

||  (loop for x = (foo)
||         when (test x)
||           do (something depending on the test))

vs

|| (loop for x = (foo)
||        while (test x)
||        do (something unconditional))

Of course, while and until are funny because in some sense if the
while or until succeeds, the entire rest of the loop is not going
to be done, so trivially it is substructure or dependent.  But
that kind of analysis would lead one to indent a loop like:

|| (loop for x = (foo)
||       while x
||         for y = (car x)
||         do (print y)
||         collect y)

which feels funny to me. I'd rather

|| (loop for x = (foo)
||       while x
||       for y = (car x)
||       do (print y)
||       collect y)
From: Joerg-Cyril Hoehle
Subject: Re: Simple LOOP question
Date: 
Message-ID: <qkpr9n2t68t.fsf@tzd.dont.telekom.spam.de.me>
Kent,

are you sure this is correct code?

Kent M Pitman <······@world.std.com> writes:
> which feels funny to me. I'd rather
> 
> || (loop for x = (foo)
> ||       while x
> ||       for y = (car x)
> ||       do (print y)
> ||       collect y)

My understanding of CLtL2 (didn't read CLHS on that topic) is that
it's not allowed to have a FOR clause following a WHILE condition.
I know some implementations which will not handle this correctly or
refuse to compile.

LOOP not powerful (confusing) enough? :-)

Regards,
	J�rg H�hle
Telekom Research Center -- SW-Reliability
From: Kent M Pitman
Subject: Re: Simple LOOP question
Date: 
Message-ID: <sfwr9n14rha.fsf@world.std.com>
············@tzd.dont.telekom.spam.de.me (Joerg-Cyril Hoehle) writes:

> Kent,
> are you sure this is correct code?
> 
> Kent M Pitman <······@world.std.com> writes:
> > which feels funny to me. I'd rather
> > 
> > || (loop for x = (foo)
> > ||       while x
> > ||       for y = (car x)
> > ||       do (print y)
> > ||       collect y)
> 
> My understanding of CLtL2 (didn't read CLHS on that topic) is that

It's worth a glance if you've not seen the syntax for LOOP.
It does make it possible to get answers to such questions.

> it's not allowed to have a FOR clause following a WHILE condition.
> I know some implementations which will not handle this correctly or
> refuse to compile.
> 
> LOOP not powerful (confusing) enough? :-)

You're right that you can't do a while between for's.
A "for" clause is a variable clause, and a "while" clause is a termination
test which is a kind of main clause.  Variable clauses must precede main 
clauses.

The example was offered for indentation and I wasn't paying attention to
what the loop actually did or even whether it was valid.  Sorry about that.
Other examples could have been constructed that illustrated the same point
legally, I guess.  Oh well.  You get what you pay for around here.
From: Pierre R. Mai
Subject: Re: Simple LOOP question
Date: 
Message-ID: <87zp2ex0zo.fsf@orion.dent.isdn.cs.tu-berlin.de>
Graham Hughes <·······@cs.ucsb.edu> writes:

> Well, one way is
> 	(loop (setq text (getname))
> 	      (if (null text) ...)
> 	      ...)
> 
> but this is not particularly functional. (Although bare loop is useful
> from time to time.)

It should be mentioned that there should at least be a binding for
text wrapped around this form, otherwise you'll be inadvertently
generating global variables (which might even be implicitly declared
special by some compilers, giving you all sorts of head-aches):

(let (text)
  (loop
    (setq text (getname))
    (if (null text)
        ;; Break out of loop, returning nil
        (return nil)
        (do-something....))))

OTOH if you're going to use bare loop, I'd pull the let binding into
the loop body, which makes this more elegant and less error-prone:

(loop
  (let ((text (getname)))
    (if (null text)
        ;; Break out of loop, returning nil
        (return nil)
        (do-something ...))))


> 	(loop for text = (getname) then (getname)
> 	      while text
>                 do ...)

The then part is not needed in loop (unlike the stepping form for do
loops), so this gives you the following nice loop idiom, which IMHO
gives the clearest indication of what you're doing:

(loop for text = (getname)
      while text
      do
      (do-something text))

The problem with most while macros I've seen, is that they simply
discard the return value of the test form, which you'll often need in
the body, thus forcing you to take care of this yourself...

> (which is due to Paul Graham) and then you can just use
> 
> (while (setq text (gettext))
>   (operate-on text))
> 
> as you're used to doing in Autolisp.

Again, the while form should be wrapped in a let to bind the text
variable first:

(let (text)
  (while (setq text (gettext))
    (operate-on text)))

All things being equal, I'd prefer a loop to explicit setq
acrobatics...

Regs, Pierre.

Disclaimer:  I didn't test any of these, so if I've overlooked
some errors, that's too bad...

-- 
Pierre Mai <····@acm.org>         PGP and GPG keys at your nearest Keyserver
  "One smaller motivation which, in part, stems from altruism is Microsoft-
   bashing." [Microsoft memo, see http://www.opensource.org/halloween1.html]
From: Graham Hughes
Subject: Re: Simple LOOP question
Date: 
Message-ID: <87r9nqflio.fsf@oak.treepeople.net>
>>>>> "Pierre" == Pierre R Mai <····@acm.org> writes:

    Pierre> Graham Hughes <·······@cs.ucsb.edu> writes:
    >> Well, one way is (loop (setq text (getname)) (if (null text) ...)
    >> ...)

    Pierre> It should be mentioned that there should at least be a
    Pierre> binding for text wrapped around this form, otherwise you'll
    Pierre> be inadvertently generating global variables (which might
    Pierre> even be implicitly declared special by some compilers,
    Pierre> giving you all sorts of head-aches):

I quite agree here, and the omission of the binding clauses on most of
my examples was very probably a mistake on my part.  Thank you :)

I can make a half-assed excuse that I was demonstrating snippets, but
you're quite right that the snippet isn't terribly useful without the
let.

<snip further discussion of bare loop>

    >> (loop for text = (getname) then (getname) while text do ...)

    Pierre> The then part is not needed in loop (unlike the stepping
    Pierre> form for do loops), so this gives you the following nice
    Pierre> loop idiom, which IMHO gives the clearest indication of what
    Pierre> you're doing:

Oh, yes, I keep forgetting about that :).  Lisp is so convenient...

    Pierre> (loop for text = (getname) while text do (do-something
    Pierre> text))

    Pierre> The problem with most while macros I've seen, is that they
    Pierre> simply discard the return value of the test form, which
    Pierre> you'll often need in the body, thus forcing you to take care
    Pierre> of this yourself...

Quite.  Paul Graham has an AWHILE to get around this, and I must say I
do like his AIF and like.

<snip my discussion of the while loop>

    Pierre> All things being equal, I'd prefer a loop to explicit setq
    Pierre> acrobatics...

Oh, I quite agree; for my own use I'd probably use the do rather than
the rest, or perhaps the loop with clauses; I just wanted to show the
original poster the range of answers possible, finishing with the one
most like what he seemed to be used to.
-- 
Graham Hughes <·······@cs.ucsb.edu>
PGP Fingerprint: 36 15 AD 83 6D 2F D8 DE  EC 87 86 8A A2 79 E7 E6
((lambda (x) (list x (list 'quote x)))
 '(lambda (x) (list x (list 'quote x))))
From: Kim-Minh Kaplan
Subject: Re: Simple LOOP question
Date: 
Message-ID: <87r9nqmlk6.fsf@kloug.western.fr>
Nir Sullam writes:

> In AutoLISP I am used to loop with while until I press Enter :
> 
> (while
>   (getname) ; read string function
>   (add to list) ; add to a list function
> )
> 
> 
> How can I do it in CL simply and without to much code ??
> 
> The CLTL is detailed but seems not to have that answer easy to find, the
> loop function seems too much for the task.

Yes, but it also seems to perform your task perfectly :

    (loop for i = (getname)
          while i
          collect i)

should return your list of functions.

Kim-minh.