From: Jeff M.
Subject: The syntax of LET
Date: 
Message-ID: <b4f08883-f411-4341-9ef8-43282b8bf7a7@8g2000hse.googlegroups.com>
I was wondering, is there a particular reason (other than preference
or readability) for chosen syntax of LET and similar forms? Is there a
problem with LET working like so:

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

It seems to me that the above form is easier to parse for the compiler
(admittedly only slightly easier) and the current method is
unnecessarily verbose. But I'm sure there's something I'm mission.
Perhaps a condition that the current form takes care of?

Jeff M.

From: Scott Burson
Subject: Re: The syntax of LET
Date: 
Message-ID: <8f51f602-3ccd-4b5e-a8dc-71f3390782d9@u10g2000prn.googlegroups.com>
On Apr 6, 7:54 am, "Jeff M." <·······@gmail.com> wrote:
> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms?

The "extra parens" leave room for some useful syntactic extensions.  I
have a `let' macro that makes it more convenient to bind variables to
the multiple values of a form, e.g.:

  (let ((a b c (foo))) ...)

expands to

  (multiple-value-bind (a b c) (foo) ...)

It does some other stuff too.  You can find it at

http://common-lisp.net/project/misc-extensions/

-- Scott
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-5CD102.10444806042008@news.gha.chartermi.net>
In article 
<····································@8g2000hse.googlegroups.com>,
 "Jeff M." <·······@gmail.com> wrote:

> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
> 
> (let (x 0 y 1 z 2) (+ x y z))

Nope.  The only downside is that if you want to initialize a variable to 
NIL you have to do it explicitly.  Not a bit loss IMHO.

> It seems to me that the above form is easier to parse for the compiler
> (admittedly only slightly easier)

Actually, it's the other way around.  Try writing the macro expansion 
for both your new LET and the old LET in terms of LAMBDA and you'll see 
that your version is actually slightly harder to parse.

> and the current method is unnecessarily verbose.

It certainly is.  However, unnecessary verbosity is not necessarily a 
bad thing.  See http://rondam.blogspot.com/2008/02/z-shrtr-bttr.html

Personally, I've become rather fond of a macro I call BB (for 
binding-block) which lets you interleave variable initializations and 
code, e.g.:

(bb
  x 1
  y 2
  (foo x y)
  :mv (q z) (bratz) ; short for multiple-value-bind
  :db (y . z) (frotz) ; short for destructuring-bind
  :with open-file (z "foo")
  (do-a-bunch-of-stuff ...))

is equivalent to:

(let* ((x 1) (y 2))
  (foo x y)
  (multiple-value-bind (q z) (bratz)
    (destructuring-bind (y . z) (frotz)
      (with-open-file (z "foo")
        (do-a-bunch-of-stuff ...)))))

You could easily get even more radical than that by having a form that 
was like PROGN but implicitly assigned a name to every form, e.g.:

(implicitly-binding-progn
  (foo) ; bound to _0
  (baz) ; bound to _1
  (bar) ; bound to _2
  (bratz _0 _1 _2))

Personally I think this is going too far, but the great thing about Lisp 
is that you don't need to be limited by my lack of imagination.

rg
From: Ken Tilton
Subject: Re: The syntax of LET
Date: 
Message-ID: <47f8ed04$0$25037$607ed4bc@cv.net>
Jeff M. wrote:
> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
> 
> (let (x 0 y 1 z 2) (+ x y z))

You are looking for Arc, which is exploring such alternatives:

   http://arclanguage.org/

> 
> It seems to me that the above form is easier to parse for the compiler
> (admittedly only slightly easier) and the current method is
> unnecessarily verbose. But I'm sure there's something I'm mission.
> Perhaps a condition that the current form takes care of?

I would say the current form takes care of the condition of your 
suggested form involving syntax. Syntax just makes things harder. Over 
on the Arc site you will find a bunch of people rapidly spiralling down 
into Perl, all because they thought the "extra parens" in let were extra 
parens.

kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"In the morning, hear the Way;
  in the evening, die content!"
                     -- Confucius
From: Scott Burson
Subject: Re: The syntax of LET
Date: 
Message-ID: <14cf7c59-5cc4-41f1-bbea-3292d076060d@u10g2000prn.googlegroups.com>
On Apr 6, 8:32 am, Ken Tilton <···········@optonline.net> wrote:
> Over
> on the Arc site you will find a bunch of people rapidly spiralling down
> into Perl, all because they thought the "extra parens" in let were extra
> parens.

Is the honeymoon over already??

-- Scott
From: Ken Tilton
Subject: Re: The syntax of LET
Date: 
Message-ID: <47f922eb$0$15171$607ed4bc@cv.net>
Scott Burson wrote:
> On Apr 6, 8:32 am, Ken Tilton <···········@optonline.net> wrote:
> 
>>Over
>>on the Arc site you will find a bunch of people rapidly spiralling down
>>into Perl, all because they thought the "extra parens" in let were extra
>>parens.
> 
> 
> Is the honeymoon over already??
> 

Honeymoon? Oh, you mean:

http://smuglispweeny.blogspot.com/2008/02/maybe-i-was-too-hard-on-sohail.html

:)

kenny

-- 
http://smuglispweeny.blogspot.com/
http://www.theoryyalgebra.com/

"I've never read the rulebook. My job is to catch the ball."
-- Catcher Josh Bard after making a great catch on a foul ball
he might have let drop and then sliding into the dugout, which
by the rules allowed the runners to advance one base costing his
pitcher a possible shutout because there was a runner
on third base.

"My sig is longer than post of my articles."
-- Kenny Tilton
From: Barry Margolin
Subject: Re: The syntax of LET
Date: 
Message-ID: <barmar-477380.15545606042008@newsgroups.comcast.net>
In article 
<····································@8g2000hse.googlegroups.com>,
 "Jeff M." <·······@gmail.com> wrote:

> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
> 
> (let (x 0 y 1 z 2) (+ x y z))
> 
> It seems to me that the above form is easier to parse for the compiler
> (admittedly only slightly easier) and the current method is
> unnecessarily verbose. But I'm sure there's something I'm mission.
> Perhaps a condition that the current form takes care of?

There's a general Lisp philosophy that lists should be used for 
grouping.  The standard LET syntax makes the grouping of a variable and 
its initializer explicit.  And as others pointed out, this grouping then 
allows for additional syntactic extensions, such as leaving out the 
initializer or extending it to multiple values.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <uod8m7n75.fsf@nhplace.com>
"Jeff M." <·······@gmail.com> writes:

> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
> 
> (let (x 0 y 1 z 2) (+ x y z))
> 
> It seems to me that the above form is easier to parse for the compiler

Lisp doesn't do "parsing", it does "reading".  The reader has no
difficulty with either format.

Once in structure, the question becomes one of grouping, and the grouping
is more natural in LET as it's done because traditionally LET meant little
more than:

 (defmacro let (bindings &body forms)
   `((lambda ,(mapcar #'first bindings))
     (mapcar #'second bindings)))

Using traditional Lisp operators, extracting and assembly the same
information from an alternating list is actually what's harder.

But independent of the difficulty issue, which is minor, most Lisp users
prefer to see the bindings grouped.  It makes it easy to grab the pair of
a name and a value and move it to another point in the list.  For example,
in:

  (let* ((x1 v1) (x2 v2)) ...)
with cursor ----^

you can re-order the two bindings in Emacs by pressing c-m-t.  If you
had

  (let* (x1 v1 x2 v2) ...)
with cursor --^

and wanted to reorder things, you'd need more operations.  Similar truths
with c-m-k, c-m-f, etc.  And in some other structure-based editors other
than Emacs, similar things apply.

> (admittedly only slightly easier) and the current method is
> unnecessarily verbose. But I'm sure there's something I'm mission.

[missing]. ;)

> Perhaps a condition that the current form takes care of?

Well, unrelated to the above, there is an additional thing you're 
missing which is that 

 (let (w x y z) ...)

already has a meaning.  It means

 (let ((w nil) (x nil) (y nil) (z nil)) ...)

although I and some other people tend to use it to mean "I didn't
initialize these yet, and the NIL is only a courtesy initialization,
not something to rely on".
From: Alex Mizrahi
Subject: Re: The syntax of LET
Date: 
Message-ID: <47f94310$0$90275$14726298@news.sunsite.dk>
 KMP> although I and some other people tend to use it to mean "I didn't
 KMP> initialize these yet, and the NIL is only a courtesy initialization,
 KMP> not something to rely on".

just curious.. is it possible to have unbound lexical variable?
if it's not possible, then why -- is this conceptually wrong in some way, or 
just assubed to be not useful? 
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <u4paey2qs.fsf@nhplace.com>
"Alex Mizrahi" <········@users.sourceforge.net> writes:

>  KMP> although I and some other people tend to use it to mean "I didn't
>  KMP> initialize these yet, and the NIL is only a courtesy initialization,
>  KMP> not something to rely on".
> 
> just curious.. is it possible to have unbound lexical variable?
> if it's not possible, then why -- is this conceptually wrong in some way, or 
> just assubed to be not useful? 

It used to be discussed from time to time and no one ever advanced a
compelling argument for why it's needed.  It's part of the heritage of
functional programming languages.  You can't get unbound lexicals in
Scheme or ML or Haskell as far as I know either.  Either a variable
name has a binding AND a value, or it doesn't have a binding.

So just as there's a theory that all functions return values whether
they want to or not (that is, there's no void type), there's also a
theory that all variables have values whether they want them or not.

Also, efficiency-wise, I suspect it works against speed because (as
I'm thinking about it just now--not something I've thought about in a
while so I may not have all relevant facts at the top of my
consciousness) it means either you have a "sufficiently clever
compiler" capable of adequate flow analysis to be able to not have to
look at every reference to see if it contains the magic unbound marker
OR ELSE it means you have to slow down every reference to the variable
just to see if the variable is bound before you access it.
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-3132C9.17150506042008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> "Alex Mizrahi" <········@users.sourceforge.net> writes:
> 
> >  KMP> although I and some other people tend to use it to mean "I didn't
> >  KMP> initialize these yet, and the NIL is only a courtesy initialization,
> >  KMP> not something to rely on".
> > 
> > just curious.. is it possible to have unbound lexical variable?
> > if it's not possible, then why -- is this conceptually wrong in some way, 
> > or 
> > just assubed to be not useful? 
> 
> It used to be discussed from time to time and no one ever advanced a
> compelling argument for why it's needed.  It's part of the heritage of
> functional programming languages.  You can't get unbound lexicals in
> Scheme or ML or Haskell as far as I know either.  Either a variable
> name has a binding AND a value, or it doesn't have a binding.
> 
> So just as there's a theory that all functions return values whether
> they want to or not (that is, there's no void type), there's also a
> theory that all variables have values whether they want them or not.
> 
> Also, efficiency-wise, I suspect it works against speed because (as
> I'm thinking about it just now--not something I've thought about in a
> while so I may not have all relevant facts at the top of my
> consciousness) it means either you have a "sufficiently clever
> compiler" capable of adequate flow analysis to be able to not have to
> look at every reference to see if it contains the magic unbound marker
> OR ELSE it means you have to slow down every reference to the variable
> just to see if the variable is bound before you access it.

Not much cleverness is required because this check can be done at 
compile time.  See http://www.flownet.com/ron/lisp/Lexicons.pdf section 
3.4.

rg
From: Joost Diepenmaat
Subject: Re: The syntax of LET
Date: 
Message-ID: <874paed5in.fsf@zeekat.nl>
"Alex Mizrahi" <········@users.sourceforge.net> writes:

>  KMP> although I and some other people tend to use it to mean "I didn't
>  KMP> initialize these yet, and the NIL is only a courtesy initialization,
>  KMP> not something to rely on".
>
> just curious.. is it possible to have unbound lexical variable?
> if it's not possible, then why -- is this conceptually wrong in some way, or 
> just assubed to be not useful? 

Unbound variables seem to me to be neither lexial, global or
special. That's (part of) what it means for vars to be unbound, right?

Somebody please correct me if I'm wrong. Cheers.

J.

-- 
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-70A724.15380806042008@news.gha.chartermi.net>
In article <··············@zeekat.nl>,
 Joost Diepenmaat <·····@zeekat.nl> wrote:

> "Alex Mizrahi" <········@users.sourceforge.net> writes:
> 
> >  KMP> although I and some other people tend to use it to mean "I didn't
> >  KMP> initialize these yet, and the NIL is only a courtesy initialization,
> >  KMP> not something to rely on".
> >
> > just curious.. is it possible to have unbound lexical variable?
> > if it's not possible, then why -- is this conceptually wrong in some way, 
> > or 
> > just assubed to be not useful? 
> 
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?

Nope.

> Somebody please correct me if I'm wrong. Cheers.

You're wrong.  To understand why start by reading:

http://www.flownet.com/ron/specials.pdf

It so happens that it is not possible to produce an unbound lexical 
variable in CL, but this is only because of the way the language is 
designed, not because it is inherently impossible or meaningless.

rg
From: Matthias Benkard
Subject: Re: The syntax of LET
Date: 
Message-ID: <b1ce36e4-f74c-4c3e-b3f3-782c6a7f79f5@a5g2000prg.googlegroups.com>
On 6 Apr., 23:42, Joost Diepenmaat <·····@zeekat.nl> wrote:
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?

It probably depends on what you mean by a "variable".

In CLHS terms, a special variable need not be bound.

CL-USER> (defvar *abc*)
*ABC*
CL-USER> (boundp '*abc*)
NIL

From CLHS 3.1.2.1.1.1:

"A lexical variable always has a value.  There is no operator that
introduces a binding for a lexical variable without giving it an
initial value, nor is there any operator that can make a lexical
variable be unbound."

From CLHS 3.1.2.1.1.2:

"The value part of the binding for a dynamic variable might be empty;
in this case, the dynamic variable is said to have no value, or to be
unbound.  A dynamic variable can be made unbound by using makunbound."

Then again, the terminology is a bit weird.  It seems that even if a
binding exists for a variable, it (the variable) may still be unbound.

~ Matthias
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <ur6diwl36.fsf@nhplace.com>
Matthias Benkard <··········@gmail.com> writes:

> On 6 Apr., 23:42, Joost Diepenmaat <·····@zeekat.nl> wrote:
> > Unbound variables seem to me to be neither lexial, global or
> > special. That's (part of) what it means for vars to be unbound, right?
> 
> It probably depends on what you mean by a "variable".
> 
> In CLHS terms, a special variable need not be bound.
> 
> CL-USER> (defvar *abc*)
> *ABC*
> CL-USER> (boundp '*abc*)
> NIL
> 
> From CLHS 3.1.2.1.1.1:
> 
> "A lexical variable always has a value.  There is no operator that
> introduces a binding for a lexical variable without giving it an
> initial value, nor is there any operator that can make a lexical
> variable be unbound."
> 
> From CLHS 3.1.2.1.1.2:
> 
> "The value part of the binding for a dynamic variable might be empty;
> in this case, the dynamic variable is said to have no value, or to be
> unbound.  A dynamic variable can be made unbound by using makunbound."

Good summary.  Expanding a little on these factoids to see how
they play out...

The complication sometimes comes because the place a global variable puts
its value is regarded by some as a binding and not by others, I guess.

The issue is further made subtle by the fact that (let ((x ...)) ...)
for a lexical variable is vaguely like CONS in effect, in that every single
time the let binding is executed, a place [or, at least, the potential for
a place, since the compiler is permitted to optimize it out] is created,
so that although the implementation of DOTIMES is explicitly permitted to
allow:
 (mapcar #'funcall
   (let ((result '()))
     (dotimes (i 3) (push #'(lambda () i) result))
       (nreverse result)))
 => (3 3 3)
or
 => (0 1 2)
you can introduce a LET to clarify your intent, and then can reliably produce
distinct closures for each iteration, as in:
 (mapcar #'funcall
   (let ((result '()))
     (dotimes (i 3) (let ((i i)) (push #'(lambda () i) result)))
     (nreverse result)))
 => (0 1 2)
will definitely produce distinct closures for each iteration.

However, a binding of a special variable, by contrast, because it does not
make a new binding every time--rather, it uses the same binding every time.

 (let ((i 'outer))
   (declare (special i))
     (loop repeat 10 collect 
       (let ((randomly (zerop (random 2))))
          (progv (if randomly (list 'i)     '())
                 (if randomly (list 'inner) '())
            ;; Sometimes this variable I will refer to an inner
            ;; special binding, and sometimes not.  But the variable
            ;; will be a special reference to i in either case, and
            ;; the reason this "works" is that "rebinding" the special
            ;; variable doesn't change what the special variable refers
            ;; to.
            i))))
 => (INNER INNER OUTER OUTER INNER OUTER OUTER OUTER INNER OUTER)

In effect, to do the same thing lexically, you have to do:

 (let ((i 'outer))
   (loop repeat 10 collect 
     (let ((randomly (zerop (random 2))))
        (if randomly
            (let ((i 'inner)) i)
            i))))
 => (INNER OUTER OUTER INNER OUTER INNER INNER OUTER OUTER INNER)

That is, there is no way to lexical bind i provisionally and yet to
use the selfsame reference to i to refer to either the inner or outer
... you either have to talk about a reference to i that is inside the
lexical binding or you have to talk about a different reference to i
that is not.

I hope this is clarifying something for people and not just confusing them.
It was hard coming up with examples to illustrate the subtlety of the issue,
but the issue is, in fact, there.

> Then again, the terminology is a bit weird.  It seems that even if a
> binding exists for a variable, it (the variable) may still be unbound.

Agreed.  Fixing this in the spec would have required making an
incompatible change to the bifurcated usage that was heavily
predominant in the Lisp community.  I wasn't up to making such a
complicated change, though I probably should have made a more modest
change by adding a modifier, as I did with separating "boolean" from
"generalized boolean" ... e.g., making up some new terms like
"lexical bindings" vs "runtime bindings" might have helped.  It caused
quite a firestorm when I did that for generalized boolean, but it was
probably good because it exposed longstanding confusions that some
people had had.  Probably there are people with similarly longstanding
confusions about bindings as the result of the wording I chose, and as
a result of my not identifying the fact of two bindings.  Ah well.
Spilled milk.
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-2A2E9D.00225407042008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> Matthias Benkard <··········@gmail.com> writes:
> 
> > On 6 Apr., 23:42, Joost Diepenmaat <·····@zeekat.nl> wrote:
> > > Unbound variables seem to me to be neither lexial, global or
> > > special. That's (part of) what it means for vars to be unbound, right?
> > 
> > It probably depends on what you mean by a "variable".
> > 
> > In CLHS terms, a special variable need not be bound.
> > 
> > CL-USER> (defvar *abc*)
> > *ABC*
> > CL-USER> (boundp '*abc*)
> > NIL
> > 
> > From CLHS 3.1.2.1.1.1:
> > 
> > "A lexical variable always has a value.  There is no operator that
> > introduces a binding for a lexical variable without giving it an
> > initial value, nor is there any operator that can make a lexical
> > variable be unbound."
> > 
> > From CLHS 3.1.2.1.1.2:
> > 
> > "The value part of the binding for a dynamic variable might be empty;
> > in this case, the dynamic variable is said to have no value, or to be
> > unbound.  A dynamic variable can be made unbound by using makunbound."
> 
> Good summary.  Expanding a little on these factoids to see how
> they play out...
> 
> The complication sometimes comes because the place a global variable puts
> its value is regarded by some as a binding and not by others, I guess.
> 
> The issue is further made subtle by the fact that (let ((x ...)) ...)
> for a lexical variable is vaguely like CONS in effect, in that every single
> time the let binding is executed, a place [or, at least, the potential for
> a place, since the compiler is permitted to optimize it out] is created,
> so that although the implementation of DOTIMES is explicitly permitted to
> allow:
>  (mapcar #'funcall
>    (let ((result '()))
>      (dotimes (i 3) (push #'(lambda () i) result))
>        (nreverse result)))
>  => (3 3 3)
> or
>  => (0 1 2)
> you can introduce a LET to clarify your intent, and then can reliably produce
> distinct closures for each iteration, as in:
>  (mapcar #'funcall
>    (let ((result '()))
>      (dotimes (i 3) (let ((i i)) (push #'(lambda () i) result)))
>      (nreverse result)))
>  => (0 1 2)
> will definitely produce distinct closures for each iteration.
> 
> However, a binding of a special variable, by contrast, because it does not
> make a new binding every time--rather, it uses the same binding every time.
> 
>  (let ((i 'outer))
>    (declare (special i))
>      (loop repeat 10 collect 
>        (let ((randomly (zerop (random 2))))
>           (progv (if randomly (list 'i)     '())
>                  (if randomly (list 'inner) '())
>             ;; Sometimes this variable I will refer to an inner
>             ;; special binding, and sometimes not.  But the variable
>             ;; will be a special reference to i in either case, and
>             ;; the reason this "works" is that "rebinding" the special
>             ;; variable doesn't change what the special variable refers
>             ;; to.
>             i))))
>  => (INNER INNER OUTER OUTER INNER OUTER OUTER OUTER INNER OUTER)
> 
> In effect, to do the same thing lexically, you have to do:
> 
>  (let ((i 'outer))
>    (loop repeat 10 collect 
>      (let ((randomly (zerop (random 2))))
>         (if randomly
>             (let ((i 'inner)) i)
>             i))))
>  => (INNER OUTER OUTER INNER OUTER INNER INNER OUTER OUTER INNER)

This might be a better example:

(let ((i 0))
   (declare (special i))
     (loop repeat 10 collect 
       (let ((randomly (zerop (random 2))))
          (progv (if randomly (list 'i)     '())
                 (if randomly (list 100) '())
            (incf i)))))

In general to make an illustrative example having to do with bindings 
you have to have mutation.  Otherwise it's impossible to distinguish 
between bindings and values.

> > Then again, the terminology is a bit weird.  It seems that even if a
> > binding exists for a variable, it (the variable) may still be unbound.
> 
> Agreed.

Huh?!?  Under what circumstances can a variable have a binding and yet 
be unbound?

rg
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <uk5j97kvp.fsf@nhplace.com>
Ron Garret <·········@flownet.com> writes:

> This might be a better example:
> 
> (let ((i 0))
>    (declare (special i))
>      (loop repeat 10 collect 
>        (let ((randomly (zerop (random 2))))
>           (progv (if randomly (list 'i)     '())
>                  (if randomly (list 100) '())
>             (incf i)))))
> 
> In general to make an illustrative example having to do with bindings 
> you have to have mutation.  Otherwise it's impossible to distinguish 
> between bindings and values.

I get a different thing out of the implementation than you do.

CL does not have multiple threads, so the example I'll give is not threadsafe.
You'd need to implement DYNAMIC-LET differently for multithreading.  But I
need a way to talk about that behavior, so I'm going to talk about it the
way that allows me to point out that your example doesn't necessarily change
the binding.

If you didn't have multithreading or PROGV, you could implement PROGV thus;
moreover, I would argue this is what some implementations do, other than a
bit of stack annotation so they can do the unwinds and winds on process 
switch.

  (defvar *unbound-marker* (list '*unbound-marker*))

  (defun evaluate-for-my-progv (vars)
    (loop for var in vars
          collect (if (boundp var)
                      (symbol-value var)
                      *unbound-marker*)))
                  
  (defun assign-for-my-progv (vars vals)
    (loop for var in vars
          for val in vals
          do (if (eq val *unbound-marker*)
                 (makunbound var)
                 (setf (symbol-value var) val))))

  (defmacro my-progv (vars-form vals-form &body forms)
    (let ((vars-var (gensym "VARS"))
          (new-vals-var (gensym "NEW-VALS"))
          (old-vals-var (gensym "OLD-VALS")))          
      `(let* ((,vars-var ,vars-form)
              (,new-vals-var ,vals-form)
              (,old-vals-var (evaluate-for-my-progv ,vars-var)))
         (unwind-protect (progn 
                           (assign-for-my-progv ,vars-var ,new-vals-var)
                           ,@forms)
           (assign-for-my-progv ,vars-var ,old-vals-var)))))

Now if you run this, you'll see that PROGV does not change the binding, it
changes the value.

 (let ((i 0))
   (declare (special i))
     (loop repeat 10 collect 
       (let ((randomly (zerop (random 2))))
         (progv (if randomly (list 'i)  '())
                (if randomly (list 100) '())
           (incf i)))))
 => (1 101 2 101 101 101 101 3 4 5)

 (let ((i 0))
   (declare (special i))
     (loop repeat 10 collect 
       (let ((randomly (zerop (random 2))))
          (my-progv (if randomly (list 'i)  '())
                    (if randomly (list 100) '())
            (incf i)))))
 => (1 101 2 3 101 4 101 101 5 6)

Moreover:

 (boundp 'foo)
 => NIL

 (my-progv '(foo) '(3) (boundp 'foo))
 => T

 (boundp 'foo)
 => NIL

And yet all those FOO's refer to the same cell.  In the working view I have,
special variables always refer to the same location, and only the values get
shuffled.  In your view, new locations are created.

(I'm kind of under the weather today, so my brain isn't at 100% capacity,
but I think if I thought harder about it I'd tell you that this issue was
just a restatement of the issue of shallow vs deep binding, upon which as
I recall CL doesn't really take a position...)

In any case, the model supports both your way of thinking about it
(that there are distinct bindings) and mine (that there are not).

> > > Then again, the terminology is a bit weird.  It seems that even if a
> > > binding exists for a variable, it (the variable) may still be unbound.
> > 
> > Agreed.
> 
> Huh?!?  Under what circumstances can a variable have a binding and yet 
> be unbound?

It depends on what you mean by binding.  My whole point is that the behavior
supports more than one theory of what a binding is.
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-2744AD.10360507042008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> Ron Garret <·········@flownet.com> writes:
> 
> > This might be a better example:
> > 
> > (let ((i 0))
> >    (declare (special i))
> >      (loop repeat 10 collect 
> >        (let ((randomly (zerop (random 2))))
> >           (progv (if randomly (list 'i)     '())
> >                  (if randomly (list 100) '())
> >             (incf i)))))
> > 
> > In general to make an illustrative example having to do with bindings 
> > you have to have mutation.  Otherwise it's impossible to distinguish 
> > between bindings and values.
> 
> I get a different thing out of the implementation than you do.
> 
> CL does not have multiple threads

Oh dear, not this again.  Every major implementation of CL except one 
(CLisp) has threads, and modern programming pretty much demands it.  If 
you're going to talk about CL in the abstract IMHO you need to assume 
threads, and treat the single-threaded case as a special case 
optimization.

It is well known that in a single-threaded environment (and ONLY in a 
single-threaded environment), dynamic binding can be implemented as 
mutation.  But IMHO that is not very interesting, and making the 
observation generally causes more confusion than it alleviates.

> > > > Then again, the terminology is a bit weird.  It seems that even if a
> > > > binding exists for a variable, it (the variable) may still be unbound.
> > > 
> > > Agreed.
> > 
> > Huh?!?  Under what circumstances can a variable have a binding and yet 
> > be unbound?
> 
> It depends on what you mean by binding.

The meaning of binding is not subject to debate.  It is defined in the 
standard:

binding n. an association between a name and that which the name 
denotes. ``A lexical binding is a lexical association between a name and 
its value.'' When the term binding is qualified by the name of a 
namespace, such as ``variable'' or ``function,'' it restricts the 
binding to the indicated namespace, as in: ``let establishes variable 
bindings.'' or ``let establishes bindings of variables.''

UNBOUND is likewise defined:

unbound adj. not having an associated denotation in a binding. See bound.

So by definition (it seems to me) to be unbound is to not have a binding.


>  My whole point is that the behavior
> supports more than one theory of what a binding is.

That may well be, but the standard does not.

rg
From: Pascal Costanza
Subject: Re: The syntax of LET
Date: 
Message-ID: <65vdk8F2ig7ccU1@mid.individual.net>
Ron Garret wrote:
> In article <·············@nhplace.com>,
>  Kent M Pitman <······@nhplace.com> wrote:
> 
>> Ron Garret <·········@flownet.com> writes:
>>
>>> This might be a better example:
>>>
>>> (let ((i 0))
>>>    (declare (special i))
>>>      (loop repeat 10 collect 
>>>        (let ((randomly (zerop (random 2))))
>>>           (progv (if randomly (list 'i)     '())
>>>                  (if randomly (list 100) '())
>>>             (incf i)))))
>>>
>>> In general to make an illustrative example having to do with bindings 
>>> you have to have mutation.  Otherwise it's impossible to distinguish 
>>> between bindings and values.
>> I get a different thing out of the implementation than you do.
>>
>> CL does not have multiple threads
> 
> Oh dear, not this again.  Every major implementation of CL except one 
> (CLisp) has threads, and modern programming pretty much demands it.  If 
> you're going to talk about CL in the abstract IMHO you need to assume 
> threads, and treat the single-threaded case as a special case 
> optimization.
> 
> It is well known that in a single-threaded environment (and ONLY in a 
> single-threaded environment), dynamic binding can be implemented as 
> mutation.  But IMHO that is not very interesting, and making the 
> observation generally causes more confusion than it alleviates.

No, you can actually implement it using mutation in multi-threaded 
environments as well, provided that the respective bindings are 
guaranteed to be thread-local.

See http://home.pipeline.com/~hbaker1/ShallowArrays.html for example.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <uwsn99uwy.fsf@nhplace.com>
Pascal Costanza <··@p-cos.net> writes:

> Ron Garret wrote:
> > In article <·············@nhplace.com>,
> >  Kent M Pitman <······@nhplace.com> wrote:
> >
> >> Ron Garret <·········@flownet.com> writes:
> > It is well known that in a single-threaded environment (and ONLY in
> > a single-threaded environment), dynamic binding can be implemented
> > as mutation.  But IMHO that is not very interesting, and making the
> > observation generally causes more confusion than it alleviates.
>
> No, you can actually implement it using mutation in multi-threaded
> environments as well, provided that the respective bindings are
> guaranteed to be thread-local.

Indeed.  My point was not to say that what I was saying was useful
only in single-threaded lisps, but rather to say the notation in which
I was trying to speak was chosen to take advantage of words that we all
already knew, so that people not familiar with multithreading issues 
could usefully read about this and reason about it.

Bringing in multithreading creates implementation challenges, but not
insurmountable ones, just ones that are (I think) irrelevant to the
current discussion and to the point I was trying to make.

In particular, I wasn't trying to write a proof using my chosen notation, 
just to illustrate the concept well enough for Ron to know what I was
speaking about.  From there, he can either choose to say he understands
or not.  I'm not trying to say he has to think like me, I'm saying he has
the choice to either understand me or to choose not to.  But I've done my
part in making my meaning clear.

> See http://home.pipeline.com/~hbaker1/ShallowArrays.html for example.

Thanks for this cross-reference, Pascal.
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-8E928C.16380107042008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> Pascal Costanza <··@p-cos.net> writes:
> 
> > Ron Garret wrote:
> > > In article <·············@nhplace.com>,
> > >  Kent M Pitman <······@nhplace.com> wrote:
> > >
> > >> Ron Garret <·········@flownet.com> writes:
> > > It is well known that in a single-threaded environment (and ONLY in
> > > a single-threaded environment), dynamic binding can be implemented
> > > as mutation.  But IMHO that is not very interesting, and making the
> > > observation generally causes more confusion than it alleviates.
> >
> > No, you can actually implement it using mutation in multi-threaded
> > environments as well, provided that the respective bindings are
> > guaranteed to be thread-local.
> 
> Indeed.  My point was not to say that what I was saying was useful
> only in single-threaded lisps, but rather to say the notation in which
> I was trying to speak was chosen to take advantage of words that we all
> already knew, so that people not familiar with multithreading issues 
> could usefully read about this and reason about it.
> 
> Bringing in multithreading creates implementation challenges, but not
> insurmountable ones, just ones that are (I think) irrelevant to the
> current discussion and to the point I was trying to make.
> 
> In particular, I wasn't trying to write a proof using my chosen notation, 
> just to illustrate the concept well enough for Ron to know what I was
> speaking about.  From there, he can either choose to say he understands
> or not.  I'm not trying to say he has to think like me, I'm saying he has
> the choice to either understand me or to choose not to.  But I've done my
> part in making my meaning clear.

I understand (or at least I think I do).  But I think you're wrong, for 
reasons that I admittedly did not explain very well.  Let me try again.

> 
> > See http://home.pipeline.com/~hbaker1/ShallowArrays.html for example.
> 
> Thanks for this cross-reference, Pascal.

First let me say that I, er, misspoke (if you'll pardon the Clintonian 
weaseling) when I wrote that dynamic binding can only be implemented as 
mutation in a single-threaded environment.  What I should have said (and 
what I actually meant but didn't actually say) was that it can be 
implemented as mutation when (and only when) there is a one-to-one 
correspondence between bindings and threads (which is, I believe, 
equivalent to what Pascal meant when he wrote "bindings are guaranteed 
to be thread-local.")

Second, let me make sure that we're on the same page about what exactly 
is at issue here.  What I think we're talking about is the claim that:

"even if a binding exists for a variable, it (the variable) may still be 
unbound."

This was originally written by Matthias Benkard, and you subsequently 
agreed with it.

I disagree with this statement.  Here are my arguments.

Argument #1 is a simple appeal to the definitions of the words "unbound" 
and "binding" in the ANSI spec, and to observe that BY DEFINITION if a 
binding exists for a variable it cannot be unbound.

I presume that the counter to this argument is to cite the phraseology 
from 3.1.2.1.1.2:

"The value part of the binding for a dynamic variable might be empty; in 
this case, the dynamic variable is said to have no value, or to be 
unbound."

Let us refer to this sentence as "sentence X."

I claim that sentence X is best regarded as a bug in the spec.  For one 
thing, there is no such thing as "the value part of a binding."  The 
word "value" is not part of the definition of "binding."  One might 
infer that "value" is a synonym for "that which the name denotes" in 
which case "binding" means "an association between a value" which makes 
a certain amount of sense and is consistent with common usage, but then 
"the value part [being] empty" is non-sensical.

Argument #2 is to refute your MY-PROGV example.  My understanding of 
MY-PROGV is that it is intended to illustrate that being "unbound" can 
be implemented by actually assigning a storage location for a variable 
and filling that storage location with a special value that indicates 
unboundedness.  (Please correct me if I'm wrong about that.)  But it 
seems to me that this is just an implementation hack, and has nothing to 
do with correctness according to the spec.

To see this, consider a compiler that emits code for lexical bindings 
that operates thusly:

1.  Adjust the stack pointer to allocate a block of memory on the stack 
to contain the values of the lexical bindings

2.  Compute the values of the lexical bindings and store them in the 
appropriate places on the stack

The fact that in between steps 1 and 2 there is a time during which 
those lexical bindings "exist" (in some sense of the word) but are not 
yet "bound" (in some sense of the word) does not change the fact that 
ACCORDING TO THE SPEC lexical bindings are ALWAYS bound.  The 
implementation is not incorrect, but the fact that these "unbound 
bindings" "exist" in some sense  at some point in time does not change 
the fact that the abstract model as specified by the spec does not admit 
these "unbound bindings."

In any case, I see nothing to be gained except confusion to treat 
sentence X as anything but a bug.

rg
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <ufxtxqcjd.fsf@nhplace.com>
Ron Garret <·········@flownet.com> writes:

> Argument #1 is a simple appeal to the definitions of the words "unbound" 
> and "binding" in the ANSI spec, and to observe that BY DEFINITION if a 
> binding exists for a variable it cannot be unbound.

My whole point was to explain BOUNDP and MAKUNBOUND in ways I've found to
match common sense.

Implementationally, these functions do not, in all implementations,
test for an absent value cell or remove the value cell.  My impression
is that in some impelmentations, they just store a marker in the cell
saying "actually, this isn't bound after all even though there's a
binding here".

And so that's how I think about it.  You, of course, may choose not to.

> I presume that the counter to this argument is to cite the phraseology 
> from 3.1.2.1.1.2:
> 
> "The value part of the binding for a dynamic variable might be empty; in 
> this case, the dynamic variable is said to have no value, or to be 
> unbound."
> 
> Let us refer to this sentence as "sentence X."
> 
> I claim that sentence X is best regarded as a bug in the spec.

Ok.  But you're appearing elsewhere to be insisting that the wording
of the spec (in the form of the definition of binding) must be taken
as gospel truth and that I'm not allowed to infer my own wording
(note: not my own semantics, merely my own way of talking about the
semantics everyone seems to agree on).  I like to use certain the term
binding more flexibly than the spec does, and I think that no harm
comes of it.

I also, incidentally, like referring to the value cell and the
function cell as slots in symbols, even though I was forbidden (in
lengthy arguments with the committee) from expressing it that way in
the spec. People seemed to fear that if I wrote the word slot, some
implementation woudl be forced to implement them that way, just in
case someone core dumped the thing and looked inside to make sure you
were wasting space.  To me, it made no difference because
implementations are free to optimize what there is nothing to prevent,
but to some people this was an issue of serious importance.

I've been thinking about bindings as I have for 30 years of Lisp use
in a variety of dialects and it hasn't caused me to get confused writing
programs, so I guess I think the notion holds up under stress in at least
one worked use-case.  Your mileage may, of course, vary.

You can argue all you want that I'm wrong.  I'm comfortable with that.
Maybe some people will even believe you.  I'm comfortable with that, too.
I don't have a goal of convincing you.  I only had a goal to say I 
disagree with you if you say there's only one way to view this--there isn't.
I've articulated another way.  You don't like it, I can see that.  But
that's ok.  I've met my goal of getting my opinion onto the record.

> Argument #2 is to refute your MY-PROGV example.  My understanding of 
> MY-PROGV is that it is intended to illustrate that being "unbound" can 
> be implemented by actually assigning a storage location for a variable 
> and filling that storage location with a special value that indicates 
> unboundedness.  (Please correct me if I'm wrong about that.)

The unboundedness is implemented by MAKUNBOUND. I have no idea how
MAKUNBOUND does it.  What I did was query BOUNDP, keep a marker in
another variable, and then restore the value via MAKUNBOUND.  That was
merely for the chance to show how it could be done, not to say it's
done any particular way.

> But it 
> seems to me that this is just an implementation hack, and has nothing to 
> do with correctness according to the spec.

None of this has anything to do with correctness according to the
spec.  As I recall, the spec was specifically written to not take
sides on the shallow/deep binding issue, and my whole point is that
it's left to implementations to sort out.

> To see this, consider a compiler that emits code for lexical bindings 
> that operates thusly:
> 
> 1.  Adjust the stack pointer to allocate a block of memory on the stack 
> to contain the values of the lexical bindings
> 
> 2.  Compute the values of the lexical bindings and store them in the 
> appropriate places on the stack
> 
> The fact that in between steps 1 and 2 there is a time during which 
> those lexical bindings "exist" (in some sense of the word) but are not 
> yet "bound" (in some sense of the word) does not change the fact that 
> ACCORDING TO THE SPEC lexical bindings are ALWAYS bound.

Certainly. I don't make any such claim.  All of my remarks are about the
abstractions, which are neutral as to implementation.  It's you, not me,
that I perceive to be saying that things have to be implemented a certain
way. I grant you that there are often pragmatic considerations that lead
in certain directions, but my point is that the spec doesn't really require
it.  And my further point is that I happen to like thinking about bindings
differently than you do, and don't find it leads to any problem.

Discussing terminology rather than effect seems odd to me.  No harm comes
from my interpretation of what a binding is.  You seem to disagree.  I doubt
you can show an example where it actually matters.  This starts to remind
me of  http://xkcd.com/171/

> The 
> implementation is not incorrect, but the fact that these "unbound 
> bindings" "exist" in some sense  at some point in time does not change 
> the fact that the abstract model as specified by the spec does not admit 
> these "unbound bindings."

Things you can't access don't make any difference.

> In any case, I see nothing to be gained except confusion to treat 
> sentence X as anything but a bug.

As I said, I disagree.  And now I'm repeating myself.  So I'll wind this
down.

Is there anything more to be learned here other than that we each have our
reasons to believe what we believe and that it probably doesn't make either
of us unable to get work done?
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-86BB83.21584307042008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> I like to use certain the term
> binding more flexibly than the spec does, and I think that no harm
> comes of it.

That is what I disagree with.  I think harm does come of it, in the form 
of confusion, particularly among people with less experience in the 
language than you or I have.

> I've been thinking about bindings as I have for 30 years of Lisp use
> in a variety of dialects and it hasn't caused me to get confused writing
> programs, so I guess I think the notion holds up under stress in at least
> one worked use-case.  Your mileage may, of course, vary.

It's a common affliction in many language communities to think that 
because the people who have been using the language for a long time have 
been able to integrate some confusing idea into their thought patterns 
that no harm comes from promulgating that confusion.  The C++ world 
suffers from this more than the CL world does, but CL suffers from it 
nonetheless.  The longer one has studied a given language the more one 
loses the ability to diagnose this affliction.

Some people actually think that this sort of confusion is a feature 
because it keeps out the riffraff.  I respectfully dissent.

> You can argue all you want that I'm wrong.  I'm comfortable with that.

Glad to hear it :-)

> Maybe some people will even believe you.  I'm comfortable with that, too.
> I don't have a goal of convincing you.

Well, I do have a goal of convincing you.  People listen to you, and I 
think you actively harm the community when newbies hear you say things 
like, "Yeah, a variable can have a binding but still be unbound."  That 
just reinforces the prejudice that some people have that CL sucks, and I 
think the community in the long run suffers for it.

> I only had a goal to say I 
> disagree with you if you say there's only one way to view this--there isn't.

I do not say that.  What I am saying is that it is less confusing to say 
that "having a binding" and "bound" mean the same thing, period, end of 
story, despite the fact that it is possible to implement dynamic binding 
in such a way that behind the scenes a dynamic variable still "has a 
binding" in some sense after calling MAKUNBOUND on it.


> It's you, not me,
> that I perceive to be saying that things have to be implemented a certain
> way.

I am not arguing for a particular implementation.  What I am arguing for 
is particular rhetoric.


> I grant you that there are often pragmatic considerations that lead
> in certain directions, but my point is that the spec doesn't really require
> it.  And my further point is that I happen to like thinking about bindings
> differently than you do, and don't find it leads to any problem.
> 
> Discussing terminology rather than effect seems odd to me.  No harm comes
> from my interpretation of what a binding is.  You seem to disagree.  I doubt
> you can show an example where it actually matters.  This starts to remind
> me of  http://xkcd.com/171/

Funny, I could have cited the same cartoon to support my position.

I say, "If a variable has a binding it is bound."  Period, end of story.

You say, "If a variable has a binding, it still might be unbound if, for 
example, the binding contains a privileged value that indicates that it 
is unbound."

To which I say, "What does all the extra complexity of your narrative 
buy you?"

And you respond ... ?


> > The 
> > implementation is not incorrect, but the fact that these "unbound 
> > bindings" "exist" in some sense  at some point in time does not change 
> > the fact that the abstract model as specified by the spec does not admit 
> > these "unbound bindings."
> 
> Things you can't access don't make any difference.

Yes!  Exactly!


> > In any case, I see nothing to be gained except confusion to treat 
> > sentence X as anything but a bug.
> 
> As I said, I disagree.  And now I'm repeating myself.  So I'll wind this
> down.
> 
> Is there anything more to be learned here other than that we each have our
> reasons to believe what we believe and that it probably doesn't make either
> of us unable to get work done?

Yes, I think there is.  This is not about you and me.  This is about the 
OP and all the others like him who are scratching their heads trying to 
figure out how a variable with a binding can be unbound, and why it 
matters.

rg
From: John Thingstad
Subject: Re: The syntax of LET
Date: 
Message-ID: <op.t87p3cweut4oq5@pandora.alfanett.no>
P� Mon, 07 Apr 2008 00:38:17 +0200, skrev Matthias Benkard  
<··········@gmail.com>:

>
> From CLHS 3.1.2.1.1.2:
>
> "The value part of the binding for a dynamic variable might be empty;
> in this case, the dynamic variable is said to have no value, or to be
> unbound.  A dynamic variable can be made unbound by using makunbound."
>
> Then again, the terminology is a bit weird.  It seems that even if a
> binding exists for a variable, it (the variable) may still be unbound.
>
> ~ Matthias

Well a global variable is bound to a symbol.
A symbol can have FUNCTION, PACKAGE, PLIST attributes as well as VALUE as  
accessed by symbol-name, symbol-package, symbol-plist and symbol-value.
So a makunbound only makes the symbol-value unbound not all the other  
attributes.
Note that this means (boundp variable) returns NIL which is different from  
(symbol-value variable) returning NIL.

--------------
John Thingstad
From: John Thingstad
Subject: Re: The syntax of LET
Date: 
Message-ID: <op.t87p8cvtut4oq5@pandora.alfanett.no>
P� Mon, 07 Apr 2008 01:27:02 +0200, skrev John Thingstad  
<·······@online.no>:

> as accessed by symbol-name, symbol-package, symbol-plist and

symbol-function not symbol-name! symbol-name gives a string denoting the  
name of the symbol.

--------------
John Thingstad
From: Barry Margolin
Subject: Re: The syntax of LET
Date: 
Message-ID: <barmar-645698.21380707042008@newsgroups.comcast.net>
In article 
<····································@a5g2000prg.googlegroups.com>,
 Matthias Benkard <··········@gmail.com> wrote:

> Then again, the terminology is a bit weird.  It seems that even if a
> binding exists for a variable, it (the variable) may still be unbound.

The word "binding" is ambiguous.  Sometimes it means the connection 
between a name and a storage location, while other times it refers to 
the contents of the storage location.  "A binding exists" refers to the 
first sense, "may still be unbound" refers to the second.

The appropriate sense can almost always be distinguished from the 
context.

-- 
Barry Margolin, ······@alum.mit.edu
Arlington, MA
*** PLEASE don't copy me on replies, I'll read them in the group ***
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <uzls6wmp7.fsf@nhplace.com>
Joost Diepenmaat <·····@zeekat.nl> writes:

> "Alex Mizrahi" <········@users.sourceforge.net> writes:
> 
> >  KMP> although I and some other people tend to use it to mean "I didn't
> >  KMP> initialize these yet, and the NIL is only a courtesy initialization,
> >  KMP> not something to rely on".
> >
> > just curious.. is it possible to have unbound lexical variable?
> > if it's not possible, then why -- is this conceptually wrong in some way, or 
> > just assubed to be not useful? 
> 
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?
> 
> Somebody please correct me if I'm wrong. Cheers.

Uh... Not entirely sure what you're saying, so hard to tell if you're
wrong or just wording things oddly or you're leaving something out ...

Notwithstanding the fact that I seem to have only put one definition
of binding in the CLHS glossary, there are really to meanings in
evidence if you look through the document.  (There may be a political
fight that prohibited me from putting both meanings, since people
think binding is some sacred term in the functional community, or it
may have been just too complicated to get the nuance right, so maybe
I just feared such a fight.  I'm quite sure I was aware of the issue.)

In fact, the word binding sometimes means these two things:

 1. The association of a symbol with a binding.

 2. The fact of the binding being a usable value.

All lexical variables use binding to mean the first thing.  In that
case, unbound means "there is no association between this name and any
lexical binding".  That is, (lambda () x) refers to an x that has no
associated lexical binding (and there are not global lexicals, so
unless x was globally special, this variable would be seen as unbound).

By contrast, having previously done (proclaim '(special *x*)) or 
(defvar *x*), and then later seeing (lambda () *x*), then *x* would refer
to the value cell of the symbol *x*, and there would really be such a thing,
but it might not contain anything [that is, it might contain a magic value
that the system has to take an extra memory cycle to check for, and which
if present means to signal an unbound variable error rather than return the
value].
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-5C7E3B.00293907042008@news.gha.chartermi.net>
In article <·············@nhplace.com>,
 Kent M Pitman <······@nhplace.com> wrote:

> That is, (lambda () x) refers to an x that has no
> associated lexical binding (and there are not global lexicals, so
> unless x was globally special, this variable would be seen as unbound).
> 
> By contrast, having previously done (proclaim '(special *x*)) or 
> (defvar *x*), and then later seeing (lambda () *x*), then *x* would refer
> to the value cell of the symbol *x*, and there would really be such a thing,
> but it might not contain anything [that is, it might contain a magic value
> that the system has to take an extra memory cycle to check for, and which
> if present means to signal an unbound variable error rather than return the
> value].

Most implementations will actually allow you to provide a binding for a 
free global reference after the fact and it will still do the "right 
thing" (for some value of "right"):

? (setf f (lambda () x))
;Compiler warnings :
;   Undeclared free variable X, in an anonymous lambda form.
#<Anonymous Function #x3000419FD72F>
? (funcall f)
> Error: Unbound variable: X
> While executing: #<Anonymous Function #x3000419FD72F>, in process Listener(111).
> Type :GO to continue, :POP to abort, :R for a list of available restarts.
> If continued: Retry getting the value of X.
> Type :? for other options.
1> 
? (defvar x 1)
X
? (funcall f)
1
? 

That is, most implementations will assume that, because there are no 
global lexicals, any free reference is a special reference even if it 
has not been explicitly declared as such.

rg
From: Joost Diepenmaat
Subject: Re: The syntax of LET
Date: 
Message-ID: <871w5imrpz.fsf@zeekat.nl>
Kent M Pitman <······@nhplace.com> writes:

> Joost Diepenmaat <·····@zeekat.nl> writes:
>
>> "Alex Mizrahi" <········@users.sourceforge.net> writes:
>> 
>> >  KMP> although I and some other people tend to use it to mean "I didn't
>> >  KMP> initialize these yet, and the NIL is only a courtesy initialization,
>> >  KMP> not something to rely on".
>> >
>> > just curious.. is it possible to have unbound lexical variable?
>> > if it's not possible, then why -- is this conceptually wrong in some way, or 
>> > just assubed to be not useful? 
>> 
>> Unbound variables seem to me to be neither lexial, global or
>> special. That's (part of) what it means for vars to be unbound, right?
>> 
>> Somebody please correct me if I'm wrong. Cheers.
>
> Uh... Not entirely sure what you're saying, so hard to tell if you're
> wrong or just wording things oddly or you're leaving something out ...

I've already been corrected about this statement in the case of CL
specifically. I mostly meant that *in general* there isn't a definite
way to resolve unboundness, though I think that CL's choice of taking
the "global/special" value is sound, or at least the most unsurprising.

> Notwithstanding the fact that I seem to have only put one definition
> of binding in the CLHS glossary, there are really to meanings in
> evidence if you look through the document.  (There may be a political
> fight that prohibited me from putting both meanings, since people
> think binding is some sacred term in the functional community, or it
> may have been just too complicated to get the nuance right, so maybe
> I just feared such a fight.  I'm quite sure I was aware of the issue.)
>
> In fact, the word binding sometimes means these two things:
>
>  1. The association of a symbol with a binding.
>
>  2. The fact of the binding being a usable value.

I may be stupid, or not interested in politics, but I just associate
binding with 1. I don't even see how something can have an "unusable
value". I can see how a var can have a useless value, though.

> All lexical variables use binding to mean the first thing.  In that
> case, unbound means "there is no association between this name and any
> lexical binding".  That is, (lambda () x) refers to an x that has no
> associated lexical binding (and there are not global lexicals, so
> unless x was globally special, this variable would be seen as unbound).

Yes, that's my intuition too, now.

> By contrast, having previously done (proclaim '(special *x*)) or 
> (defvar *x*), and then later seeing (lambda () *x*), then *x* would refer
> to the value cell of the symbol *x*, and there would really be such a thing,
> but it might not contain anything [that is, it might contain a magic value
> that the system has to take an extra memory cycle to check for, and which
> if present means to signal an unbound variable error rather than return the
> value].

Ok, I think I'm getting a handle on what you're saying above. Thanks for
taking the time to explain this. I'll sleep on it. :-)

-- 
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
From: ·······@eurogaran.com
Subject: Re: The syntax of LET
Date: 
Message-ID: <29ab5127-a6c2-4ef0-bb83-eae12efb7f34@n1g2000prb.googlegroups.com>
> I mostly meant that *in general* there isn't a definite
> way to resolve unboundness
It were nice that garbage collection would be also exerted on symbols -
not only on data- so any unbound symbol (without function or any other
value) could be reclaimed and disappear from the environment,
including the results of doing (do-all-symbols) and the like.
From: Mark Wooding
Subject: Re: The syntax of LET
Date: 
Message-ID: <slrnfvint8.ckr.mdw@metalzone.distorted.org.uk>
Joost Diepenmaat <·····@zeekat.nl> wrote:

> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?
>
> Somebody please correct me if I'm wrong. Cheers.

(defvar *special*)
(boundp '*special*) 			; => NIL

Common Lisp's concept of bound-ness doesn't quite match up with the
usual one -- it adds an extra requirement of `having a value'.

Certainly, a symbol is always `bound' in the sense that we know where to
find its value -- either it's lexically bound, in which case we pluck
the value out of the appropriate run-time environment frame, or it's
not, in which case we use the symbol's value cell.  The complication is
that there might not actually be a proper value there when we find it.

As an aside on implementation, SBCL (and presumably other
implementations) actually works by having a magical not-a-value marker
which it puts in the symbol's value-cell; SLOT-BOUNDP and friends apply
the same concept to the slots of CLOS classes, and in pretty much the
same way (SBCL actually just uses the symbol SB-PCL::..SLOT-UNBOUND.. as
its marker).

Given this state of affairs, there doesn't seem much reason why there
couldn't in principle be `unbound lexical variables'.  But checking a
symbol's value-cell for bound-ness takes time, and it was probably
thought that it wasn't worth slowing down access to lexical variables
just because there might be a use for making them be unbound.  (That
said, the compiler will be able to notice whether a lexical variable
could be referred to while in an unbound state, so maybe it wouldn't be
such a loss after all.  It still doesn't seem particularly useful, and
inventing your own unique magic-marker-value isn't difficult.)

-- [mdw]
From: Joost Diepenmaat
Subject: Re: The syntax of LET
Date: 
Message-ID: <8763uumsrf.fsf@zeekat.nl>
Mark Wooding <···@distorted.org.uk> writes:

> Given this state of affairs, there doesn't seem much reason why there
> couldn't in principle be `unbound lexical variables'.  But checking a
> symbol's value-cell for bound-ness takes time, and it was probably
> thought that it wasn't worth slowing down access to lexical variables
> just because there might be a use for making them be unbound.  (That
> said, the compiler will be able to notice whether a lexical variable
> could be referred to while in an unbound state, so maybe it wouldn't be
> such a loss after all.  It still doesn't seem particularly useful, and
> inventing your own unique magic-marker-value isn't difficult.)

So how, for the sake of argument would an implementation figure out that
an unbound variable would be lexical instead of global, and especially,
what scope the unbound lexical should have?

-- 
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
From: Kent M Pitman
Subject: Re: The syntax of LET
Date: 
Message-ID: <uskxygy3j.fsf@nhplace.com>
Joost Diepenmaat <·····@zeekat.nl> writes:

> Mark Wooding <···@distorted.org.uk> writes:
> 
> > Given this state of affairs, there doesn't seem much reason why there
> > couldn't in principle be `unbound lexical variables'.  But checking a
> > symbol's value-cell for bound-ness takes time, and it was probably
> > thought that it wasn't worth slowing down access to lexical variables
> > just because there might be a use for making them be unbound.  (That
> > said, the compiler will be able to notice whether a lexical variable
> > could be referred to while in an unbound state, so maybe it wouldn't be
> > such a loss after all.  It still doesn't seem particularly useful, and
> > inventing your own unique magic-marker-value isn't difficult.)
> 
> So how, for the sake of argument would an implementation figure out that
> an unbound variable would be lexical instead of global, and especially,
> what scope the unbound lexical should have?

The classification of variables into lexical and global are things that
can be done statically.  A brief explanation of the issue is in the
background of this issue, which was a failing proposal for CL to acquire
toplevel lexical variables:

http://www.nhplace.com/kent/CL/Issues/proclaim-lexical.html
From: John Thingstad
Subject: Re: The syntax of LET
Date: 
Message-ID: <op.t87no6v7ut4oq5@pandora.alfanett.no>
P� Sun, 06 Apr 2008 23:42:40 +0200, skrev Joost Diepenmaat  
<·····@zeekat.nl>:

> "Alex Mizrahi" <········@users.sourceforge.net> writes:
>
>>  KMP> although I and some other people tend to use it to mean "I didn't
>>  KMP> initialize these yet, and the NIL is only a courtesy  
>> initialization,
>>  KMP> not something to rely on".
>>
>> just curious.. is it possible to have unbound lexical variable?
>> if it's not possible, then why -- is this conceptually wrong in some  
>> way, or
>> just assubed to be not useful?
>
> Unbound variables seem to me to be neither lexial, global or
> special. That's (part of) what it means for vars to be unbound, right?
>
> Somebody please correct me if I'm wrong. Cheers.
>
> J.
>

Well the variable is assumed special.

(defun silly ()
   (print unbound))

But the compiler gives a warning about this.
If you intend to use a special variable include a (declare (special  
*variable*)).

Variables declared by let/let* will have have value.
As a style guide I try never declare a variable until I have a reasonable  
value to assign to it.
Giving a variable a bogus value like nil if it makes no sense is almost as  
bad as not declaring it.

--------------
John Thingstad
From: Joost Diepenmaat
Subject: Re: The syntax of LET
Date: 
Message-ID: <87zls6bnvu.fsf@zeekat.nl>
"John Thingstad" <·······@online.no> writes:

> På Sun, 06 Apr 2008 23:42:40 +0200, skrev Joost Diepenmaat
>> Unbound variables seem to me to be neither lexial, global or
>> special. That's (part of) what it means for vars to be unbound, right?
>>
>> Somebody please correct me if I'm wrong. Cheers.
>
> Well the variable is assumed special.
>
> (defun silly ()
>   (print unbound))
>
> But the compiler gives a warning about this.
> If you intend to use a special variable include a (declare (special
> *variable*)).

I should have known this. I've seen the warning often enough, and it
sort of makes sense to have an unbound var be special (or at least
global). Anyway, thanks to you and the others who replied.

Cheers,
Joost.

-- 
Joost Diepenmaat | blog: http://joost.zeekat.nl/ | work: http://zeekat.nl/
From: Pascal Costanza
Subject: Re: The syntax of LET
Date: 
Message-ID: <65vnimF2gm641U1@mid.individual.net>
Alex Mizrahi wrote:
>  KMP> although I and some other people tend to use it to mean "I didn't
>  KMP> initialize these yet, and the NIL is only a courtesy initialization,
>  KMP> not something to rely on".
> 
> just curious.. is it possible to have unbound lexical variable?
> if it's not possible, then why -- is this conceptually wrong in some way, or 
> just assubed to be not useful? 

The question is what unboundness is typically used for. I see two uses:

+ To make it explicit that a variable hasn't been initialized yet. 
Reading it will throw an exception (and not just return nil, as other 
languages would, which will make initialization errors occur only much 
later and make them much harder to debug).

+ In CLOS objects, slot unboundness can additionally be used to perform 
lazy initialization, by defining methods on slot-unbound. (Very useful! 
Would actually be useful for global variables as well.)

These two use cases make sense especially for global variables and CLOS 
slots because the code that first uses a particular global variable or a 
particular slot may be located in a completely different part of some 
source code then the respective variable definition / object 
instantiation. Having an extra mechanism to indicate uninitialized use 
early is helpful because it may otherwise be very hard to track down 
what happened.

However, for lexical variables, the only code that can actually read and 
write them is textually enclosed. Since it's a good rule of thumb to 
keep function definitions small, it should generally be relatively 
straightforward to detect whether a variable has been properly 
initialized before its first use, and implementing lazy initialization 
mechanisms for lexical variables is also not rocket science.

That's just a guess why unboundness is not so useful for lexical 
variables, but it seems to me to make sense.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Pascal Costanza
Subject: Re: The syntax of LET
Date: 
Message-ID: <65vqrcF2i1vf6U1@mid.individual.net>
Pascal Costanza wrote:
> However, for lexical variables, the only code that can actually read and 
> write them is textually enclosed. Since it's a good rule of thumb to 
> keep function definitions small, it should generally be relatively 
> straightforward to detect whether a variable has been properly 
> initialized before its first use, and implementing lazy initialization 
> mechanisms for lexical variables is also not rocket science.
> 
> That's just a guess why unboundness is not so useful for lexical 
> variables, but it seems to me to make sense.

To wit:
(defvar %unbound% (list 'unbound))

(defun prepare-binding (binding)
   (etypecase binding
     (symbol (list binding %unbound%))
     (cons (assert (car binding))
           (assert (null (cddr binding)))
           (list (first binding)
                 (if (rest binding)
                   (second binding)
                   %unbound%)))))

(defun parse-bindings (bindings)
   (loop for binding in bindings
         for (var expr) = (prepare-binding binding)
         collect var into vars
         collect (copy-symbol var) into ivars
         collect expr into exprs
         finally (return (values vars ivars exprs))))

(defmacro ulet ((&rest bindings) &body body)
   (multiple-value-bind
       (vars ivars exprs)
       (parse-bindings bindings)
     `(let ,(loop for ivar in ivars
                  collect `(,ivar %unbound%))
        (flet ,(loop for ivar in ivars
                     collect `((setf ,ivar) (new-value)
                                (setf ,ivar new-value)))
          (flet
              ,(loop
                for var in vars
                for ivar in ivars
                for expr in exprs
                collect `(,ivar ()
                           (if (eq ,ivar %unbound%)
                             ,(if (eq expr %unbound%)
                                `(error "Unbound variable ~S." ',var)
                                expr)
                             ,ivar)))
            (symbol-macrolet ,(loop for var in vars
                                    for ivar in ivars
                                    collect `(,var (,ivar)))
              ,@body))))))


 > (ulet ((x (print 42))
          (y (print 88)))
     y)

88
88

 > (ulet (x y) y)

Error: Unbound variable Y.

 > (ulet ((x (print 42))
          (y (print 88)))
     (setq x 111)
     (+ x y))

88
199



Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-1B32A5.18154507042008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Pascal Costanza wrote:
> > However, for lexical variables, the only code that can actually read and 
> > write them is textually enclosed. Since it's a good rule of thumb to 
> > keep function definitions small, it should generally be relatively 
> > straightforward to detect whether a variable has been properly 
> > initialized before its first use, and implementing lazy initialization 
> > mechanisms for lexical variables is also not rocket science.
> > 
> > That's just a guess why unboundness is not so useful for lexical 
> > variables, but it seems to me to make sense.
> 
> To wit:
> (defvar %unbound% (list 'unbound))
> 
> (defun prepare-binding (binding)
>    (etypecase binding
>      (symbol (list binding %unbound%))
>      (cons (assert (car binding))
>            (assert (null (cddr binding)))
>            (list (first binding)
>                  (if (rest binding)
>                    (second binding)
>                    %unbound%)))))
> 
> (defun parse-bindings (bindings)
>    (loop for binding in bindings
>          for (var expr) = (prepare-binding binding)
>          collect var into vars
>          collect (copy-symbol var) into ivars
>          collect expr into exprs
>          finally (return (values vars ivars exprs))))
> 
> (defmacro ulet ((&rest bindings) &body body)
>    (multiple-value-bind
>        (vars ivars exprs)
>        (parse-bindings bindings)
>      `(let ,(loop for ivar in ivars
>                   collect `(,ivar %unbound%))
>         (flet ,(loop for ivar in ivars
>                      collect `((setf ,ivar) (new-value)
>                                 (setf ,ivar new-value)))
>           (flet
>               ,(loop
>                 for var in vars
>                 for ivar in ivars
>                 for expr in exprs
>                 collect `(,ivar ()
>                            (if (eq ,ivar %unbound%)
>                              ,(if (eq expr %unbound%)
>                                 `(error "Unbound variable ~S." ',var)
>                                 expr)
>                              ,ivar)))
>             (symbol-macrolet ,(loop for var in vars
>                                     for ivar in ivars
>                                     collect `(,var (,ivar)))
>               ,@body))))))
> 
> 
>  > (ulet ((x (print 42))
>           (y (print 88)))
>      y)
> 
> 88
> 88
> 
>  > (ulet (x y) y)
> 
> Error: Unbound variable Y.
> 
>  > (ulet ((x (print 42))
>           (y (print 88)))
>      (setq x 111)
>      (+ x y))
> 
> 88
> 199

Also:

? (ulet (x) (print (nth-value 1 (ignore-errors x))) (setf x 1) x)

#<SIMPLE-ERROR #x3000419EB41D> 
1
? 

rg
From: Pascal Costanza
Subject: Re: The syntax of LET
Date: 
Message-ID: <660meeF2io9qeU1@mid.individual.net>
Ron Garret wrote:
> In article <···············@mid.individual.net>,
>  Pascal Costanza <··@p-cos.net> wrote:
> 
>> Pascal Costanza wrote:
>>> However, for lexical variables, the only code that can actually read and 
>>> write them is textually enclosed. Since it's a good rule of thumb to 
>>> keep function definitions small, it should generally be relatively 
>>> straightforward to detect whether a variable has been properly 
>>> initialized before its first use, and implementing lazy initialization 
>>> mechanisms for lexical variables is also not rocket science.
>>>
>>> That's just a guess why unboundness is not so useful for lexical 
>>> variables, but it seems to me to make sense.
>> To wit:
>> (defvar %unbound% (list 'unbound))
>>
>> (defun prepare-binding (binding)
>>    (etypecase binding
>>      (symbol (list binding %unbound%))
>>      (cons (assert (car binding))
>>            (assert (null (cddr binding)))
>>            (list (first binding)
>>                  (if (rest binding)
>>                    (second binding)
>>                    %unbound%)))))
>>
>> (defun parse-bindings (bindings)
>>    (loop for binding in bindings
>>          for (var expr) = (prepare-binding binding)
>>          collect var into vars
>>          collect (copy-symbol var) into ivars
>>          collect expr into exprs
>>          finally (return (values vars ivars exprs))))
>>
>> (defmacro ulet ((&rest bindings) &body body)
>>    (multiple-value-bind
>>        (vars ivars exprs)
>>        (parse-bindings bindings)
>>      `(let ,(loop for ivar in ivars
>>                   collect `(,ivar %unbound%))
>>         (flet ,(loop for ivar in ivars
>>                      collect `((setf ,ivar) (new-value)
>>                                 (setf ,ivar new-value)))
>>           (flet
>>               ,(loop
>>                 for var in vars
>>                 for ivar in ivars
>>                 for expr in exprs
>>                 collect `(,ivar ()
>>                            (if (eq ,ivar %unbound%)
>>                              ,(if (eq expr %unbound%)
>>                                 `(error "Unbound variable ~S." ',var)
>>                                 expr)
>>                              ,ivar)))
>>             (symbol-macrolet ,(loop for var in vars
>>                                     for ivar in ivars
>>                                     collect `(,var (,ivar)))
>>               ,@body))))))
>>
>>
>>  > (ulet ((x (print 42))
>>           (y (print 88)))
>>      y)
>>
>> 88
>> 88
>>
>>  > (ulet (x y) y)
>>
>> Error: Unbound variable Y.
>>
>>  > (ulet ((x (print 42))
>>           (y (print 88)))
>>      (setq x 111)
>>      (+ x y))
>>
>> 88
>> 199
> 
> Also:
> 
> ? (ulet (x) (print (nth-value 1 (ignore-errors x))) (setf x 1) x)
> 
> #<SIMPLE-ERROR #x3000419EB41D> 
> 1
> ? 

Yes, of course. From the HyperSpec:

"ignore-errors executes forms in a dynamic environment where a handler 
for conditions of type error has been established; if invoked, it 
handles such conditions by returning two values, nil and the condition 
that was signaled, from the ignore-errors form."


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Ron Garret
Subject: Re: The syntax of LET
Date: 
Message-ID: <rNOSPAMon-7B991C.09205808042008@news.gha.chartermi.net>
In article <···············@mid.individual.net>,
 Pascal Costanza <··@p-cos.net> wrote:

> Ron Garret wrote:
> > In article <···············@mid.individual.net>,
> >  Pascal Costanza <··@p-cos.net> wrote:
> > 
> >> Pascal Costanza wrote:
> >>> However, for lexical variables, the only code that can actually read and 
> >>> write them is textually enclosed. Since it's a good rule of thumb to 
> >>> keep function definitions small, it should generally be relatively 
> >>> straightforward to detect whether a variable has been properly 
> >>> initialized before its first use, and implementing lazy initialization 
> >>> mechanisms for lexical variables is also not rocket science.
> >>>
> >>> That's just a guess why unboundness is not so useful for lexical 
> >>> variables, but it seems to me to make sense.
> >> To wit:
> >> (defvar %unbound% (list 'unbound))
> >>
> >> (defun prepare-binding (binding)
> >>    (etypecase binding
> >>      (symbol (list binding %unbound%))
> >>      (cons (assert (car binding))
> >>            (assert (null (cddr binding)))
> >>            (list (first binding)
> >>                  (if (rest binding)
> >>                    (second binding)
> >>                    %unbound%)))))
> >>
> >> (defun parse-bindings (bindings)
> >>    (loop for binding in bindings
> >>          for (var expr) = (prepare-binding binding)
> >>          collect var into vars
> >>          collect (copy-symbol var) into ivars
> >>          collect expr into exprs
> >>          finally (return (values vars ivars exprs))))
> >>
> >> (defmacro ulet ((&rest bindings) &body body)
> >>    (multiple-value-bind
> >>        (vars ivars exprs)
> >>        (parse-bindings bindings)
> >>      `(let ,(loop for ivar in ivars
> >>                   collect `(,ivar %unbound%))
> >>         (flet ,(loop for ivar in ivars
> >>                      collect `((setf ,ivar) (new-value)
> >>                                 (setf ,ivar new-value)))
> >>           (flet
> >>               ,(loop
> >>                 for var in vars
> >>                 for ivar in ivars
> >>                 for expr in exprs
> >>                 collect `(,ivar ()
> >>                            (if (eq ,ivar %unbound%)
> >>                              ,(if (eq expr %unbound%)
> >>                                 `(error "Unbound variable ~S." ',var)
> >>                                 expr)
> >>                              ,ivar)))
> >>             (symbol-macrolet ,(loop for var in vars
> >>                                     for ivar in ivars
> >>                                     collect `(,var (,ivar)))
> >>               ,@body))))))
> >>
> >>
> >>  > (ulet ((x (print 42))
> >>           (y (print 88)))
> >>      y)
> >>
> >> 88
> >> 88
> >>
> >>  > (ulet (x y) y)
> >>
> >> Error: Unbound variable Y.
> >>
> >>  > (ulet ((x (print 42))
> >>           (y (print 88)))
> >>      (setq x 111)
> >>      (+ x y))
> >>
> >> 88
> >> 199
> > 
> > Also:
> > 
> > ? (ulet (x) (print (nth-value 1 (ignore-errors x))) (setf x 1) x)
> > 
> > #<SIMPLE-ERROR #x3000419EB41D> 
> > 1
> > ? 
> 
> Yes, of course. From the HyperSpec:
> 
> "ignore-errors executes forms in a dynamic environment where a handler 
> for conditions of type error has been established; if invoked, it 
> handles such conditions by returning two values, nil and the condition 
> that was signaled, from the ignore-errors form."

Right.  My point was just to illustrate that in that case X is actually 
unbound (or at least behaves as if it is unbound) until you assign a 
value to it, whereupon it becomes bound.

Symbol macros are really quite cool.

rg
From: Pascal Costanza
Subject: Re: The syntax of LET
Date: 
Message-ID: <65sa9fF2hv3k7U1@mid.individual.net>
Jeff M. wrote:
> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
> 
> (let (x 0 y 1 z 2) (+ x y z))

In Common Lisp, (let (x y z) ...) is short for
(let ((x nil) (y nil) (z nil)) ...). The idea is that with (let (x y z) 
...) you introduce new variables, but you indicate to readers that you 
don't intend any initialization at this stage yet.

With your shorter version, making such intentions clear wouldn't be 
possible anymore.

Apart from that, that's a micro issue. There are more important things 
to worry about than getting such detailed design issues right. In large 
programs, this gets lost in the noise.


Pascal

-- 
1st European Lisp Symposium (ELS'08)
http://prog.vub.ac.be/~pcostanza/els08/

My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Harald Hanche-Olsen
Subject: Re: The syntax of LET
Date: 
Message-ID: <pcor6djotp1.fsf@shuttle.math.ntnu.no>
+ "Jeff M." <·······@gmail.com>:

> Is there a problem with LET working like so:
>
> (let (x 0 y 1 z 2) (+ x y z))

It might be slightly harder to write a macro that builds up a let form
on this form.  That is not a very strong reason, but it just might be
one of several reasons for the current choice.

-- 
* Harald Hanche-Olsen     <URL:http://www.math.ntnu.no/~hanche/>
- It is undesirable to believe a proposition
  when there is no ground whatsoever for supposing it is true.
  -- Bertrand Russell
From: Pascal Bourguignon
Subject: Re: The syntax of LET
Date: 
Message-ID: <87od8nhssg.fsf@thalassa.informatimago.com>
"Jeff M." <·······@gmail.com> writes:

> I was wondering, is there a particular reason (other than preference
> or readability) for chosen syntax of LET and similar forms? Is there a
> problem with LET working like so:
>
> (let (x 0 y 1 z 2) (+ x y z))
>
> It seems to me that the above form is easier to parse for the compiler
> (admittedly only slightly easier) and the current method is
> unnecessarily verbose. But I'm sure there's something I'm mission.
> Perhaps a condition that the current form takes care of?

Why don't you try?

(shadow 'let)
(defmacro let (bindings &body body)
  (assert (evenp (length bindings)))
  `(cl:let ,(loop :for (var val) :on bindings :by (function cddr)
                  :collect (list var val)) ,@body))


C/USER1[103]> (let (x 0 y 1 z 2) (+ x y z))
3

Yep, seems to work well.

-- 
__Pascal Bourguignon__                     http://www.informatimago.com/

ADVISORY: There is an extremely small but nonzero chance that,
through a process known as "tunneling," this product may
spontaneously disappear from its present location and reappear at
any random place in the universe, including your neighbor's
domicile. The manufacturer will not be responsible for any damages
or inconveniences that may result.