Google Groups no longer supports new Usenet posts or subscriptions. Historical content remains viewable.
Dismiss

Duplicate identifiers in let - difference between CL and Scheme

95 views
Skip to first unread message

jurgen_defurne

unread,
Oct 22, 2012, 7:46:09 AM10/22/12
to
Hello,

While trying out some things, I noticed there is a big difference in interpretation between CL and Scheme for the following expression:

(let ((a 100)
(a 200))
(print a)) ;;e.g.

In Common Lisp the value 200 is printed, in Scheme an error occurs.

Is this for backwards compatibility of CL with older Lisps, is this to make it easier to implement, or are there other reasons?

I must say that I have already written some programs in Common Lisp, some not so easy, e.g. a simulation of microprocessor on the signal level, and I have not had the problem that I by accident created variables with almost the same name, and then had typos. Common Lisp invites for a strong decomposition, which together with almost no restrictions on identifiers, lowers the chance of name clashes.

Taking it then from the Scheme side: is there advantage in detecting name clashes, aside from it being part of the Scheme standard?

Regards,

Jurgen

Nils M Holm

unread,
Oct 22, 2012, 7:50:05 AM10/22/12
to
jurgen_defurne <jurgen....@pandora.be> wrote:
> (let ((a 100)
> (a 200))
> (print a)) ;;e.g.
>
> Taking it then from the Scheme side: is there advantage in detecting
> name clashes, aside from it being part of the Scheme standard?

(let ((a 100) (a 200)) (display a))

is merely some syntactic sugar coating for

((lambda (a a) (display a)) 100 200)

So which "a" would you like to print in your function?

--
Nils M Holm < n m h @ t 3 x . o r g > www.t3x.org

jurgen_defurne

unread,
Oct 22, 2012, 8:01:31 AM10/22/12
to
Op maandag 22 oktober 2012 13:50:07 UTC+2 schreef Nils M Holm het volgende:
Well, it is not about which 'a' I want to print, it is more about why one language accepts this code and the other language gives an error, even though they are both based on the same fundamentals.

Regards,

Espen Vestre

unread,
Oct 22, 2012, 8:15:35 AM10/22/12
to
jurgen_defurne <jurgen....@pandora.be> writes:

> Well, it is not about which 'a' I want to print, it is more about why
> one language accepts this code and the other language gives an error,
> even though they are both based on the same fundamentals.

I think you're confusing "language" with "implementation" here. Since
the ANSI spec says that the LET-bindings should be performed in
parallel, I'd say that binding the same variable twice is implicitely
illegal i Common Lisp.

Implementations don't even agree with themselves :-)
- the LispWorks interpreter will give you 100, while the compiler compiles
*with warnings* to something that gives you 200:

CL-USER 8 > (defun foobar ()
(let ((a 100)
(a 200))
(print a)))
FOOBAR

CL-USER 9 > (foobar)

100
100

CL-USER 10 > (compile 'foobar)
;;;*** Warning in FOOBAR: Variable name duplicated in lambda list or LET: A
;;;*** Warning in FOOBAR: A is bound but not referenced
FOOBAR
((NIL #<CONDITIONS::SIMPLE-COMPILER-WARNING 4020007513> #<CONDITIONS::SIMPLE-STYLE-WARNING 4020007D7B>))
T

CL-USER 11 > (foobar)

200
200

CL-USER 12 >

--
(espen)

Nils M Holm

unread,
Oct 22, 2012, 8:19:39 AM10/22/12
to
jurgen_defurne <jurgen....@pandora.be> wrote:
> Op maandag 22 oktober 2012 13:50:07 UTC+2 schreef Nils M Holm het volgende:
> > jurgen_defurne wrote:
> > > (let ((a 100)
> > > (a 200))
> > > (print a)) ;;e.g.
> > >
> > > Taking it then from the Scheme side: is there advantage in detecting
> > > name clashes, aside from it being part of the Scheme standard?
> >
> > (let ((a 100) (a 200)) (display a))
> >
> > is merely some syntactic sugar coating for
> >
> > ((lambda (a a) (display a)) 100 200)
> >
> > So which "a" would you like to print in your function?
>
> Well, it is not about which 'a' I want to print,

Yes, it is, because being able to tell which "a" to print is an
advantage to detecing name clashes. Which is an answer to your
original question.

> it is more about
> why one language accepts this code and the other language gives an
> error, even though they are both based on the same fundamentals.

jurgen_defurne

unread,
Oct 22, 2012, 8:22:48 AM10/22/12
to
Op maandag 22 oktober 2012 14:15:35 UTC+2 schreef Espen Vestre het volgende:
I supposed so, but I did not find anything about it in the CLHS or CLtL.
So that probably means that it is up to the implementation to do with it what they want. E.g. in CLISP and SBCL I do not get any warnings at all.

In R5RS it is explicitly stated:
*It is an error for a <variable> to appear more than once in the list of variables being bound.*

Regards,

Pascal J. Bourguignon

unread,
Oct 22, 2012, 8:23:34 AM10/22/12
to
That's because there are different ways to implement a let operator,
that different lisps had different behavior there.

Common Lisp mostly defined a greatest common denominator of all lisp
practices current at the time.

Notice that Common Lisp doesn't specify that (let ((a 100)(a 200)) a)
should return 200. It is undefined by the standard. It could as well
return 100. Or something else:

[pjb@kuiper :0 Body]$ clall -r '(let ((a 100) (a 200)) a)'

International Allegro CL Free Express Edition --> 100
Clozure Common Lisp --> 200
CLISP --> 200
CMU Common Lisp Repeated variable in lambda-list: A.
ECL --> 100
SBCL Execution of a form compiled with errors. Form: (LET ((A 100) (A 200)) A) Compile-time error: The variable A occurs more than once in the LET.

In CL, (let ((a 100) (a 200)) a) is non conforming code, and should
not be used.



Another difference between scheme and CL let, is that in CL, the
evaluation of the initialization forms is done from left to right, while
the order is not determined in scheme.

In scheme:

(let ((a 1))
(let ((b (begin (set! a (+ 1 a)) a))
(c (begin (set! a (+ 1 a)) a)))
(list b c)))
--> 2 3 ; or
--> 3 2

In CL,

(let ((a 1))
(let ((b (incf a))
(c (incf a)))
(list b c)))
--> 2 3

But notice how a scheme program can be as well a CL conforming program.


Since the order of evaluation is not specified in scheme, and since the
presence of duplicate variables is not specified in CL, you can write a
scheme let form that is a valid CL form.


--
__Pascal Bourguignon__ http://www.informatimago.com/
A bad day in () is better than a good day in {}.

jurgen_defurne

unread,
Oct 22, 2012, 8:26:30 AM10/22/12
to
Op maandag 22 oktober 2012 14:19:39 UTC+2 schreef Nils M Holm het volgende:
> jurgen_defurne wrote:
>
> > Op maandag 22 oktober 2012 13:50:07 UTC+2 schreef Nils M Holm het volgende:
>
> > > jurgen_defurne wrote:
>
> > > > (let ((a 100)
>
> > > > (a 200))
>
> > > > (print a)) ;;e.g.
>
> > > >
>
> > > > Taking it then from the Scheme side: is there advantage in detecting
>
> > > > name clashes, aside from it being part of the Scheme standard?
>
> > >
>
> > > (let ((a 100) (a 200)) (display a))
>
> > >
>
> > > is merely some syntactic sugar coating for
>
> > >
>
> > > ((lambda (a a) (display a)) 100 200)
>
> > >
>
> > > So which "a" would you like to print in your function?
>
> >
>
> > Well, it is not about which 'a' I want to print,
>
>
>
> Yes, it is, because being able to tell which "a" to print is an
> advantage to detecting name clashes. Which is an answer to your
> original question.

Can you elaborate on that? Are you talking about a mechanism with which to select either of the 'a' variables, instead of letting the compiler stop on a name clash?

Regards,

jurgen_defurne

unread,
Oct 22, 2012, 8:28:16 AM10/22/12
to
Op maandag 22 oktober 2012 14:15:35 UTC+2 schreef Espen Vestre het volgende:
I suppose also that if a Common Lisp implementation was created which raised an exception on this kind of code, that some programs might not work anymore?

Regards,

Espen Vestre

unread,
Oct 22, 2012, 8:44:13 AM10/22/12
to
jurgen_defurne <jurgen....@pandora.be> writes:

> I suppose also that if a Common Lisp implementation was created which
> raised an exception on this kind of code, that some programs might not
> work anymore?

That would be defective programs, then. I maintain that this is
implicitly not allowed by CL, since it's not possible to bind the same
variable twice *in parallel*.

Note that using the same variable twice makes sense in LET* and does not
conflict with the definition in the standard (and the LW compiler is
happy with it), but I'd personally consider it bad style.
--
(espen)

Pascal J. Bourguignon

unread,
Oct 22, 2012, 11:17:48 AM10/22/12
to
jurgen_defurne <jurgen....@pandora.be> writes:

> I suppose also that if a Common Lisp implementation was created which
> raised an exception on this kind of code, that some programs might not
> work anymore?

Only non conforming programs. But who cares if non conforming programs
don't work anyway?

Benjamin Kreuter

unread,
Oct 22, 2012, 1:51:38 PM10/22/12
to
On Mon, 22 Oct 2012 05:28:16 -0700 (PDT)
jurgen_defurne <jurgen....@pandora.be> wrote:

> I suppose also that if a Common Lisp implementation was created which
> raised an exception on this kind of code, that some programs might
> not work anymore?

I believe that such an implementation has already been created; at
least on my system, sbcl gives me this:

Form:
(LET ((A 1) (A 2))
(PRINT A))
Compile-time error:
The variable A occurs more than once in the lambda list.

-- Ben



--
Benjamin R Kreuter
UVA Computer Science
brk...@virginia.edu
KK4FJZ

--

"If large numbers of people are interested in freedom of speech, there
will be freedom of speech, even if the law forbids it; if public
opinion is sluggish, inconvenient minorities will be persecuted, even
if laws exist to protect them." - George Orwell

Helmut Eller

unread,
Oct 23, 2012, 2:54:17 AM10/23/12
to
On Mon, Oct 22 2012, jurgen_defurne wrote:

> In R5RS it is explicitly stated:
> *It is an error for a <variable> to appear more than once in the list
> of variables being bound.*

The phrase "it is an error" in R5RS is not the same as "the
implementation must detect the error". Implementations a free to ignore
the issue, e.g. Scheme48 ignores it. The meaning of "it is an error" is
closer to a "pilot error".

Helmut

Barry Margolin

unread,
Oct 23, 2012, 9:44:37 AM10/23/12
to
In article <m2k3uhl...@gmail.com>,
So it's analogous to the CL spec's "consequences are undefined".

--
Barry Margolin, bar...@alum.mit.edu
Arlington, MA
*** PLEASE post questions in newsgroups, not directly to me ***

Jeff Barnett

unread,
Oct 23, 2012, 2:02:31 PM10/23/12
to
On 10/22/2012 5:50 AM, Nils M Holm wrote:
> jurgen_defurne <jurgen....@pandora.be> wrote:
>> (let ((a 100)
>> (a 200))
>> (print a)) ;;e.g.
>>
>> Taking it then from the Scheme side: is there advantage in detecting
>> name clashes, aside from it being part of the Scheme standard?
>
> (let ((a 100) (a 200)) (display a))
>
> is merely some syntactic sugar coating for
>
> ((lambda (a a) (display a)) 100 200)
>
> So which "a" would you like to print in your function?
>
Careful: Let's change your example to

(let*(b ...) (declare ...) body)

versus

((lambda(b ...) (declare ...) body) presets)

and I ask whether they are still the "same". At one point, the common
Lisp spec had them potentially different. I thought that wasn't a good
idea. However, I had little influence and, at least in the old days,
they were different depending on what declarations you used.
--
Jeff Barnett
0 new messages