From: Michael Beattie
Subject: a noob question
Date: 
Message-ID: <qOVId.5834$4Z6.2220@fe12.lga>
Why is it that some macros or whatever have double parens around them? 
Like...

(let ((x 2))) ; this has 2 parens around the x=2 assignment

or

(do ((i 0 (+ i 1)))  ; there's 2 parens around the i=0 and the increment
   ((> i 10) 'done) ; 2 parens around the "end" condition
   (print i))

I guess part of the question is "what exactly is the template for the do 
  or let macro?"



Mike Beattie

From: Tayssir John Gabbour
Subject: Re: a noob question
Date: 
Message-ID: <1106523406.016058.322580@z14g2000cwz.googlegroups.com>
Michael Beattie wrote:
> Why is it that some macros or whatever have double parens around
> them? Like...
>
> (let ((x 2))) ; this has 2 parens around the x=2 assignment
>
> or
>
> (do ((i 0 (+ i 1)))  ; there's 2 parens around the i=0 and the
increment
>    ((> i 10) 'done) ; 2 parens around the "end" condition
>    (print i))
>
> I guess part of the question is "what exactly is the template for
> the do or let macro?"

Good questiron. LET's syntax is:

let ({var | (var [init-form])}*) declaration* form* => result*

If we did away with having a single "var" without an initform, which is
probably sucky practice anyway, we could do without the multiple
parens:

.  (let (blah 10
.        foo  20
.        bar  30)
.    (+ blah foo bar))

I'm guessing the Ancients didn't think of it, or really liked tacitly
initting stuff to nil. I recall Paul Graham complaining about this once
while talking about Arc. And if you think about it, setf actually is
like this when you're setting multiple things at once.

.  (defmacro let- ((&rest inits) &body body)
.    `(let ,(loop for i on inits by #'cddr
.                 collect (list (first i) (second i)))
.      ,@body))


At the prompt:

.  CL-USER> (macroexpand '(let- (blah 10
.                                foo  20
.                                bar  30)
.                           (list blah foo bar)))
.
.  (let ((blah 10)
.        (foo  20)
.        (bar  30))
.    (list blah foo bar))
.  t


MfG,
Tayssir
From: Tayssir John Gabbour
Subject: Re: a noob question
Date: 
Message-ID: <1106525232.460436.217610@f14g2000cwb.googlegroups.com>
Tayssir John Gabbour wrote:
> .  (defmacro let- ((&rest inits) &body body)
> .    `(let ,(loop for i on inits by #'cddr
> .                 collect (list (first i) (second i)))
> .      ,@body))

Hmm, a nicer version of LET- would be something like:

.  (defmacro let- (inits &body body)
.    "Like LET, except does away with a redundant level of parens.
.
.  The syntax is: let ({pair}*) declaration* form* => result*
.                 pair::= var initform
.
.  Unlike LET, no var may be without an initform."
.    (unless (listp inits)
.      (error "let-: init forms need to be within a list. ~S is not a
list." inits))
.    (unless (evenp (length inits))
.      (error "let-: an even number of init forms is needed. Found only
~A forms.~%~S" (length inits) inits))
.    `(let ,(loop for i on inits by #'cddr
.                 collect (list (first i) (second i)))
.      ,@body))

Wrestling with Google Groups was a bit frustrating in my last post...
Incidentally, that's why there's all those dots prefixing my code,
since GG won't indent my posts as I wish.


MfG,
Tayssir
From: Surendra Singhi
Subject: Re: a noob question
Date: 
Message-ID: <ct1tpv$4ui$1@news.asu.edu>
Tayssir John Gabbour wrote:
> At the prompt:
> 
> .  CL-USER> (macroexpand '(let- (blah 10
> .                                foo  20
> .                                bar  30)
> .                           (list blah foo bar)))
> .
> .  (let ((blah 10)
> .        (foo  20)
> .        (bar  30))
> .    (list blah foo bar))
> .  t

What if one doesn't wants to intitialise the variables?
Should one be forced to write!!
                  (blah nil
                   foo nil
                   bar nil)

We need a better solution.

--
Surendra Singhi

www.public.asu.edu/~sksinghi/
From: drewc
Subject: Re: a noob question
Date: 
Message-ID: <YW0Jd.157003$6l.92903@pd7tw2no>
Surendra Singhi wrote:
> Tayssir John Gabbour wrote:
> 
>> At the prompt:
>>
>> .  CL-USER> (macroexpand '(let- (blah 10
>> .                                foo  20
>> .                                bar  30)
>> .                           (list blah foo bar)))
>> .
>> .  (let ((blah 10)
>> .        (foo  20)
>> .        (bar  30))
>> .    (list blah foo bar))
>> .  t
> 
> 
> What if one doesn't wants to intitialise the variables?
> Should one be forced to write!!
>                  (blah nil
>                   foo nil
>                   bar nil)
> 
> We need a better solution.

Isn't that called 'LET' ?

CL-USER> (let (a b c d)
	   (values a b c d))
NIL
NIL
NIL
NIL
CL-USER>

perhaps i'm confused as to what we are trying to do here. A general let 
that does both types of declaration? how would you parse that?

Personally, i prefer the LET- macro to let, as i think we should be 
forced to explicitly initialize to nil (or an actual value of the type 
the variable will hold so DECLARE and the like will work).

Then again, a couple extra parens don't bother me much.

drewc

 >
 > --
 > Surendra Singhi
 >
 > www.public.asu.edu/~sksinghi/
From: Tayssir John Gabbour
Subject: Re: a noob question
Date: 
Message-ID: <1106586926.518592.278490@f14g2000cwb.googlegroups.com>
Surendra Singhi wrote:
> Tayssir John Gabbour wrote:
> > At the prompt:
> >
> > .  CL-USER> (macroexpand '(let- (blah 10
> > .                                foo  20
> > .                                bar  30)
> > .                           (list blah foo bar)))
> > .
> > .  (let ((blah 10)
> > .        (foo  20)
> > .        (bar  30))
> > .    (list blah foo bar))
> > .  t
>
> What if one doesn't wants to intitialise the variables?
> Should one be forced to write!!
>                   (blah nil
>                    foo nil
>                    bar nil)
>
> We need a better solution.

Clearly, you solve this problem with LET-+:

.  ;; no error checking
.  (defmacro let-+ ((&rest initforms) &body body)
.    `(let- ,(loop for i in initforms
.                  if (listp i)
.                     append i
.                  else append (list i nil))
.      ,@body))


And it's quite trivial to define a macro-generating macro which does
this for things like LET-+-+-+-+. So all your bases are covered, by the
rules of induction. It's MATHEMATICS. Us computing people like
MATHEMATICS, don't we? You can't possibly argue with MATHEMATICS. Break
me off a piece of that MATHEMATICS! Because I like MATHEMATICS.

PS: Anyone have nice Emacs fonts for Greek letters? Because it looks a
lot like MATHEMATICS. Everything conforms to the rules of MATHEMATICS.
I saw a bus drive past the other day, and I was like pi*r^2, baby! It's
all just MATHEMATICS.

Ahem.


MfG,
Tayssir
From: Tayssir John Gabbour
Subject: Re: a noob question
Date: 
Message-ID: <1106621262.494313.224820@c13g2000cwb.googlegroups.com>
Tayssir John Gabbour wrote:
> .  (let (blah 10
> .        foo  20
> .        bar  30)
> .    (+ blah foo bar))
>
> I'm guessing the Ancients didn't think of it, or really liked tacitly
> initting stuff to nil. I recall Paul Graham complaining about this
once
> while talking about Arc. And if you think about it, setf actually is
> like this when you're setting multiple things at once.

Actually, one big strike is that Emacs doesn't easily indent the above
code properly by default. (I don't know how simple it is to teach it to
Emacs.) You see this as a justification in packages like Iterate, that
a more "Lispy" approach is nicer for Emacs indentation than (say) LOOP.
MfG,
Tayssir
From: Trent Buck
Subject: Re: a noob question
Date: 
Message-ID: <20050125195722.6785d4a8@harpo.marx>
Up spake Tayssir John Gabbour:
> > .  (let (blah 10
> > .        foo  20
> > .        bar  30)
> > .    (+ blah foo bar))
> >
> > I'm guessing the Ancients didn't think of it, or really liked tacitly
> > initting stuff to nil. I recall Paul Graham complaining about this once
> > while talking about Arc. And if you think about it, setf actually is
> > like this when you're setting multiple things at once.
> 
> Actually, one big strike is that Emacs doesn't easily indent the above
> code properly by default.

...because it's been taught not to -- i.e. it treats LET differently to
an ordinary function.  Today I typed CASE instead of COND by accident,
and it idented it `incorrectly' (and thus I found the bug).

-- 
-trent
My last girlfriend was cute, but then I found
out she was a rom, so I had to dump her.
From: Tayssir John Gabbour
Subject: Re: a noob question
Date: 
Message-ID: <1106661104.328161.133760@f14g2000cwb.googlegroups.com>
Trent Buck wrote:
> Up spake Tayssir John Gabbour:
> > > .  (let (blah 10
> > > .        foo  20
> > > .        bar  30)
> > > .    (+ blah foo bar))
> > >
> > Actually, one big strike is that Emacs doesn't easily indent the
above
> > code properly by default.
>
> ...because it's been taught not to -- i.e. it treats LET differently
> to an ordinary function.  Today I typed CASE instead of COND by
> accident, and it idented it `incorrectly' (and thus I found the bug).

In this case, if it weren't named LET but rather GARBLE, it would still
exhibit similar indentation behavior for the init-pairs, at least on my
machine. (I just tested it out.)

Maybe it's not such a big deal, just remembered things like Iterate
occasionally mention that as a peripheral point.


MfG,
Tayssir
From: Paul F. Dietz
Subject: Re: a noob question
Date: 
Message-ID: <3bKdnZy4FsXkumncRVn-jg@dls.net>
Michael Beattie wrote:
> Why is it that some macros or whatever have double parens around them? 
> Like...
> 
> (let ((x 2))) ; this has 2 parens around the x=2 assignment
> 
> or
> 
> (do ((i 0 (+ i 1)))  ; there's 2 parens around the i=0 and the increment
>   ((> i 10) 'done) ; 2 parens around the "end" condition
>   (print i))
> 
> I guess part of the question is "what exactly is the template for the do 
>  or let macro?"

Because these can have more than one binding.

   (let ((x 1) (y 2)) (+ x y)) ==> 3

The end condition of DO is grouped with the end form(s), so it doesn't get
confused with the body of the DO.

	Paul
From: Michael Beattie
Subject: Re: a noob question
Date: 
Message-ID: <1sWId.6597$2s6.517@fe12.lga>
Paul F. Dietz wrote:
> Michael Beattie wrote:
> 
>> Why is it that some macros or whatever have double parens around them? 
>> Like...
>>
>> (let ((x 2))) ; this has 2 parens around the x=2 assignment
>>
>> or
>>
>> (do ((i 0 (+ i 1)))  ; there's 2 parens around the i=0 and the increment
>>   ((> i 10) 'done) ; 2 parens around the "end" condition
>>   (print i))
>>
>> I guess part of the question is "what exactly is the template for the 
>> do  or let macro?"
> 
> 
> Because these can have more than one binding.
> 
>   (let ((x 1) (y 2)) (+ x y)) ==> 3
> 
> The end condition of DO is grouped with the end form(s), so it doesn't get
> confused with the body of the DO.
> 
>     Paul

Sure, but you can have more than one grouping as such:

(let (x 1) (y 2)) (+ x y)

though that isnt going to work since x and y wont exist outside of that 
last paren I guess...  It makes sense to me, but it just seems odd... 
like why wouldnt it try to evaluate that (x 1) which is invalid in itself.

Maybe I am just thinking too much.

As for the do... I think it's weird that it would take 3 arguments, 
where the first one is actually 3 arguments, and the second one is like 
2 or whatever and then the last one is the body.  I would think it more 
intuitive to be like:

(do (i 1 (+ i 1) (> i 10) 'done) (print i))
From: Bruce Stephens
Subject: Re: a noob question
Date: 
Message-ID: <87651nyaqh.fsf@cenderis.demon.co.uk>
Michael Beattie <········@alumni.rutgers.edu> writes:

[...]

> Sure, but you can have more than one grouping as such:
>
> (let (x 1) (y 2)) (+ x y)

That would more clearly be written:

     (let (x 1) (y 2))
     (+ x y)

> though that isnt going to work since x and y wont exist outside of
> that last paren I guess...  It makes sense to me, but it just seems
> odd... like why wouldnt it try to evaluate that (x 1) which is
> invalid in itself.

     (let (x y) ...)

is valid.  I guess let could be hacked such that (x 1) worked, but
then it's only invalid because 1 isn't a symbol, so the idea would
only work for a limited set of things.

[...]
From: Pascal Bourguignon
Subject: Re: a noob question
Date: 
Message-ID: <87acqzofrw.fsf@thalassa.informatimago.com>
Michael Beattie <········@alumni.rutgers.edu> writes:

> Paul F. Dietz wrote:
> > Michael Beattie wrote:
> >
> >> Why is it that some macros or whatever have double parens around
> >> them? Like...
> >>
> >> (let ((x 2))) ; this has 2 parens around the x=2 assignment
> >>
> >> or
> >>
> >> (do ((i 0 (+ i 1)))  ; there's 2 parens around the i=0 and the increment
> >>   ((> i 10) 'done) ; 2 parens around the "end" condition
> >>   (print i))
> >>
> >> I guess part of the question is "what exactly is the template for
> >> the do  or let macro?"

Read the reference: CLHS
http://www.lispworks.com/reference/HyperSpec/Body/s_let_l.htm
http://www.lispworks.com/reference/HyperSpec/Body/m_do_do.htm


You must not think "parenthesis" 
(there is absolutely NO parenthesis in lisp!),
but _lists_.


Ok, I hear you people not believing me that there's no parenthesis in
lisp. Try this:

(defun dump-sexp (sexp &optional (level ""))
  (if (atom sexp)
      (format t "~AATOM: ~A~%" level sexp)
      (progn (format t "~ALIST:~%" level)
             (mapcar (lambda (x) (dump-sexp x (concatenate 'string level " ")))
                      sexp))))

[2]> (dump-sexp '(if (zerop x) 1 (1- x)))

LIST:
 ATOM: IF
 LIST:
  ATOM: ZEROP
  ATOM: X
 ATOM: 1
 LIST:
  ATOM: 1-
  ATOM: X

Where are the parentheses?

Or try this:

[47]> (com.informatimago.common-lisp.cons-to-ascii:draw-list '(if (zerop x) 1 (1- x)))

+-----------------------------------------------------------+
|                                                           |
|                                                           |
| +---+---+   +---+---+   +---+---+   +---+---+             |
| | * | * |-->| * | * |-->| * | * |-->| * |NIL|             |
| +---+---+   +---+---+   +---+---+   +---+---+             |
|   |           |           |           |                   |
|   v           |           v           v                   |
| +----+        |         +---+       +---+---+   +---+---+ |
| | IF |        |         | 1 |       | * | * |-->| * |NIL| |
| +----+        |         +---+       +---+---+   +---+---+ |
|               |                       |           |       |
|               |                       v           v       |
|               |                     +----+      +---+     |
|               |                     | 1- |      | X |     |
|               |                     +----+      +---+     |
|               v                                           |
|             +---+---+   +---+---+                         |
|             | * | * |-->| * |NIL|                         |
|             +---+---+   +---+---+                         |
|               |           |                               |
|               v           v                               |
|             +-------+   +---+                             |
|             | ZEROP |   | X |                             |
|             +-------+   +---+                             |
+-----------------------------------------------------------+

Can you see any parenthesis?



> > Because these can have more than one binding.
> >   (let ((x 1) (y 2)) (+ x y)) ==> 3
> > The end condition of DO is grouped with the end form(s), so it
> > doesn't get
> > confused with the body of the DO.
> >     Paul
> 
> Sure, but you can have more than one grouping as such:
> 
> (let (x 1) (y 2)) (+ x y)
> 
> though that isnt going to work since x and y wont exist outside of
> that last paren I guess...  It makes sense to me, but it just seems
> odd... like why wouldnt it try to evaluate that (x 1) which is invalid
> in itself.
> 
> Maybe I am just thinking too much.

Yes you are. Try to parse: (let (f 1) (g (f 1)) (x 1))
 

> As for the do... I think it's weird that it would take 3 arguments,
> where the first one is actually 3 arguments, and the second one is
> like 2 or whatever and then the last one is the body.  I would think
> it more intuitive to be like:
> 
> (do (i 1 (+ i 1) (> i 10) 'done) (print i))

How could you write the following loop then?

(defun 2^n (n)
  (do ((i 0 (1+ i))
       (j 1 (* 2 j)))
      ((= i n) j)))


-- 
__Pascal Bourguignon__                     http://www.informatimago.com/
Our enemies are innovative and resourceful, and so are we. They never
stop thinking about new ways to harm our country and our people, and
neither do we. -- Georges W. Bush
From: Kaz Kylheku
Subject: Re: a noob question
Date: 
Message-ID: <1106679378.682590.99900@z14g2000cwz.googlegroups.com>
Michael Beattie wrote:
> Paul F. Dietz wrote:
> > Michael Beattie wrote:
> >
> >> Why is it that some macros or whatever have double parens around
them?
> >> Like...
> >>
> >> (let ((x 2))) ; this has 2 parens around the x=2 assignment

[ ... ]

> > Because these can have more than one binding.
> >
> >   (let ((x 1) (y 2)) (+ x y)) ==> 3
> >

[ ... ]

>
> Sure, but you can have more than one grouping as such:
>
> (let (x 1) (y 2)) (+ x y)
>
> though that isnt going to work since x and y wont exist outside of
that
> last paren I guess...

That's right. So what you have is two objects printed side by side, not
one single expression.

You have to stop thinking in terms of parentheses and tokens, and see
the list structure. Lisp source isn't really text, but a data structure
(which has a printed representation that is the predominant means by
which people specify that data structure).

In the syntax for LET, since you have zero or more bindings, and zero
or more forms to be evaluated (and possible declarations before them),
the list structure has to be such that you know which constituents are
bindings and which are forms to be evaluated.

Firstly, this rules out everything being in a list. The syntax for LET
cannot be something like:

(let <binding-0> ... <binding-n> <form-0> ... <form-n>)

If that were the case, then the binding forms would have to have some
distinguishing feature or there would have to be some marker in between
the two lists so you could tell where the forms begin.

The usual answer is to turn the first of the two subsequences into a
list, which then occupies a single fixd position in the syntax,
Everything after that is the second list:

(let (<binding-0> ... <binding-n>) <form-0> ... <form-n>)

So now the question is, why are the binding forms themselves lists?
That is to say, why not just:

(let (x 1 y 2) ...)

rather than

(let ((x 1) (y 2)) ...)

There are some shrewd and experienced thinkers in the Lisp world,
notably Paul Graham, who think that this is just a historic leftover
that can be left out of new language designs. His Arc language in fact
has a LET which works like the first example. The list of bindings
resembles a property list. But of course this means that every variable
has to have an initial value. If you delete one of the initial values,
it screws up the position-based syntax which requires the variable
symbols to be in the even positions of the list, and initial values to
occupy the odd positions.

In Lisp, the form can be a list like (x 1) or it can just be a symbol
like x, in which case the implicit initial value is NIL. In other
words, the following syntax is valid:

(let (x y) ...)

it sets up X and Y as variables holding the value NIL. See? No extra
parentheses there.

> It makes sense to me, but it just seems odd...
> like why wouldnt it try to evaluate that (x 1) which is invalid in
itself.

Aha, okay. Good question. Why not just allow the syntax to be quite
loose like that, and make the compiler or macro smarter? The macro can
try parsing the syntax in various ways, and reduce it down to the set
which make sense, and then pick among them according to some precedence
heuristics. Sure. (x 1) is ``obviously'' not trying to declare 1 as a
variable, so it must the the initial value for x. :)

The problem is that the software isn't any more flexible; it just has
more rules. And now everyone who wants to do custom processing over a
LET has to faithfully reproduce all those rules!

What's worse, the machine silently accepts syntax that may be the
result of a mistake by giving it some ``obvious'' interpretation.

For instance, say I wanted:

(let (x 'y) ...)

which ``obviously'' means that the expression 'Y which produces the
symbol Y is to be evaluated to form the initial value of X. Suppose I
accidentally left out the quote and wrote:

(let (x y) ...)

We have two variables now, and X's initial value is NIL. To make the
same mistake in Common Lisp, you'd have to make two mistakes: forget
the quote and the parentheses: (let ((x 'y)) ...).  If you just forgot
the quote, then you are initializing X to the value of Y, something
that can be caught as an error if Y has no binding.


> Maybe I am just thinking too much.
>
> As for the do... I think it's weird that it would take 3 arguments,
> where the first one is actually 3 arguments, and the second one is
like
> 2 or whatever and then the last one is the body.  I would think it
more
> intuitive to be like:
>
> (do (i 1 (+ i 1) (> i 10) 'done) (print i))


Yeah, except that DO can initialize and increment more than one
variable, and the termination test can evaluate more than one form
also.

(do ((i 1 (+ i 1))
(j 3 (+ j 4)))
((> i 10) (format t "done!~%"))
(format t "i = ~a, j = ~a~%" i j))

output:

i = 1, j = 3
i = 2, j = 7
i = 3, j = 11
i = 4, j = 15
i = 5, j = 19
i = 6, j = 23
i = 7, j = 27
i = 8, j = 31
i = 9, j = 35
i = 10, j = 39
done!


Again, you could reduce the list structure if you reduce some of the
flexibility of the syntax. If you forced the programmer to have an
initial value for each variable and an incrementing expression, the
design could be:

  (do (i 1 (+ i 1)
       j 3 (+ j 4)) ...)
From: Edi Weitz
Subject: Re: a noob question
Date: 
Message-ID: <uhdl7sqtz.fsf@agharta.de>
On Sun, 23 Jan 2005 17:41:29 -0500, Michael Beattie <········@alumni.rutgers.edu> wrote:

> I guess part of the question is "what exactly is the template for
> the do or let macro?"

You know where to find the ANSI spec, don't you?

  <http://www.lispworks.com/documentation/HyperSpec/Front/index.htm>

Edi.

-- 

Lisp is not dead, it just smells funny.

Real email: (replace (subseq ·········@agharta.de" 5) "edi")
From: Fred Gilham
Subject: Re: a noob question
Date: 
Message-ID: <u7zmyyuxar.fsf@snapdragon.csl.sri.com>
Michael Beattie <········@alumni.rutgers.edu> writes:

> Why is it that some macros or whatever have double parens around them? 
> Like...
> 
> (let ((x 2))) ; this has 2 parens around the x=2 assignment
> 
> or
> 
> (do ((i 0 (+ i 1)))  ; there's 2 parens around the i=0 and the increment
>    ((> i 10) 'done) ; 2 parens around the "end" condition
>    (print i))
> 
> I guess part of the question is "what exactly is the template for the do 
>   or let macro?"

You've received a number of answers so far, but here's a
"list-oriented" way to think about it.  (After all, Lisp is a
"list-processing" language, right?)

The basic unit of Lisp is the form.  A form is either some atomic
object or a list.  Both LET and DO forms are lists.

LET forms take a list of bindings and a sequence of zero or more "body
forms" that it evaluates in the current lexical environment extended
by the bindings.  (The whole purpose of LET forms are to extend the
current lexical environment with new bindings.  If that is
gobbledy-gook to you, you should try to find out what it means.)  The
value of the last of the sequence of body-forms is the return value of
the LET form.

(let binding-list body-forms)

A binding list is a list of zero or more bindings.

(let (binding binding binding ....) body-forms)

A binding is either 

1) a symbol 

or

2) a list of a symbol and a form to evaluate to get the value of the
variable the symbol names.

(let (symbol1
      (symbol2 form)
      ...)
  body-forms)

For example:

(let (symbol1                  ; No value, defaults to NIL.
      (symbol2 3)              ; Initial value 3.
      (symbol3 'foo)           ; Initial value 'foo.
      (symbol4 (sqrt 10000)))  ; Initial value (sqrt 10000).
  (setf symbol2 (* symbol2 symbol4)) ; Body form 1.
  symbol2)                           ; Body form 2, returned as value.

A DO form is like a LET form with a few differences.

(do binding-list end-list body-forms)

or

(do (binding binding binding ...) (end-test result-forms) body-forms)

A binding in a DO form is like a binding in a LET form but it has one
extra possibility.  It is

1) a symbol,

or

2)  a list containing a symbol and a form to get the symbol's initial
value, 

*or* 

3) a list of a symbol, an initial value form, and a form to give the
symbol a new value upon each iteration of the do.

The end-list is a list consisting of an end test and a sequence of
forms to evaluate, the last of which is the return value of the DO
form.  The end test is simply any form that returns a value.  If it
returns nil, the end-test is false; if it returns anything else the
end-test is true and the DO loop terminates.

(do (symbol1         ; No initial value (default NIL). No iteration form.
     (symbol2 0)     ; Initial value but no iteration form.
     (symbol3 0 (1+ symbol3))) ; Both initial value and iteration form.
    ((> symbol3 10) (incf symbol1) (values symbol1 symbol2)); End test
                                                            ; and two return forms.
  (incf symbol2)                      ; Body form 1.
  (setf symbol1 (+ symbol2 symbol3))  ; Body form 2.
)

It helps me at least to think of things this way.

-- 
Fred Gilham                                     ······@csl.sri.com
I mean what's Stanford doing teaching Java?  That's not education,
it's vocational training.                        -- Bruce Stephens
From: Fred Gilham
Subject: Re: a noob question
Date: 
Message-ID: <u7wtu2uv10.fsf@snapdragon.csl.sri.com>
I wrote:
>     ((> symbol3 10) (incf symbol1) (values symbol1 symbol2)); End test
>                                                             ; and two return forms.

Of course, only the second form, the values form, actually returns
here.  These are "end forms" not "return forms".

-- 
Fred Gilham                                        ······@csl.sri.com
The spam folder --- you will never find a more wretched hive of scum
and villainy.  We must be cautious.
From: Rob Warnock
Subject: Re: a noob question
Date: 
Message-ID: <m86dnacrGNdl6WrcRVn-1w@speakeasy.net>
Fred Gilham  <······@snapdragon.csl.sri.com> wrote:
+---------------
| I wrote:
| >     ((> symbol3 10) (incf symbol1) (values symbol1 symbol2)); End test
| >                                                             ; and two
| return forms.
| 
| Of course, only the second form, the values form, actually returns
| here.  These are "end forms" not "return forms".
+---------------

And of course, the "(incf symbol1)" will
blow up, since "symbol1" was bound to NIL.  ;-}  ;-}


-Rob

-----
Rob Warnock			<····@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607