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

Repeated lambda variables

50 views
Skip to first unread message

David Gadbois

unread,
Jan 6, 1999, 3:00:00 AM1/6/99
to
Is ((LAMBA (FOO FOO) FOO) 1 2) legal ANS Common Lisp? The HyperSpec
does not appear to have an answer.

The arguments against it being legal basically boil down to allowing
implementations to note specifically what is almost certainly a
programming error.

The arguments for it being legal are 1) It does not appear to be ruled
out; and 2) There is a sensible interpretation of what it means (the
rightmost binding shadows any to the left of it.)

On the implementation front, both the Genera 8.3 and CMU CL 18a
interpreters and compilers give an error about the repeated variable.
The clisp and LispWorks interpreters return 2, and their compilers
issue warnings about the variable FOO (presumably the first one) not
being used.

--David Gadbois

Rainer Joswig

unread,
Jan 6, 1999, 3:00:00 AM1/6/99
to

MCL says:

> Error: While compiling an anonymous function :
> Bad lambda list : (FOO FOO)

--
http://www.lavielle.com/~joswig

Rainer Joswig

unread,
Jan 6, 1999, 3:00:00 AM1/6/99
to

Lyman S. Taylor

unread,
Jan 6, 1999, 3:00:00 AM1/6/99
to
In article <w0ksodo...@lagavulin.cyc.com>,
David Gadbois <gad...@lagavulin.cyc.com> wrote:
>Is ((LAMBA (FOO FOO) FOO) 1 2) legal ANS Common Lisp? The HyperSpec
>does not appear to have an answer.

I guess it depends a bit upon how literally you interpret the HyperSpec

lambda list n. a list that specifies a set of parameters (sometimes called
lambda variables) and a protocol for receiving values for
those parameters;

The first part of that defintion mentions "set". An implication
that duplicates aren't allowed, IMHO.

I can't seem to find anything protesting about

(let ( ( a 1 )
( b 2 )
( a 3 ) )
a )

either. However, I wouldn't expect any standard behaviour.


>The arguments for it being legal are 1) It does not appear to be ruled
>out;

Left out can also implicitly mean implementation specific. Not
required. The standard being larely a document for what the implementation
must do.

--

Lyman S. Taylor "I'm a Doctor! Not a commando."
(ly...@cc.gatech.edu) The enhanced EMH Doctor in a ST:Voyager epidsode.

Barry Margolin

unread,
Jan 6, 1999, 3:00:00 AM1/6/99
to
In article <770jgj$3...@pravda.cc.gatech.edu>,

Lyman S. Taylor <ly...@cc.gatech.edu> wrote:
>In article <w0ksodo...@lagavulin.cyc.com>,
>David Gadbois <gad...@lagavulin.cyc.com> wrote:
> I can't seem to find anything protesting about
>
> (let ( ( a 1 )
> ( b 2 )
> ( a 3 ) )
> a )
>
> either. However, I wouldn't expect any standard behaviour.

I thought I remembered this coming up, but I can't find anything in the HS,
either. I thought that we decided that LET doesn't allow duplication,
while LET* does, but I can't find it.

>>The arguments for it being legal are 1) It does not appear to be ruled
>>out;
>
> Left out can also implicitly mean implementation specific. Not
> required. The standard being larely a document for what the implementation
> must do.

The standard doesn't say that this is an error. However, it is also silent
about which value the parameter variable should be bound to initially. All
the required variables are supposed to be bound in parallel, so it's
unspecified which value it should receive.

--
Barry Margolin, bar...@bbnplanet.com
GTE Internetworking, Powered by BBN, Burlington, MA
*** DON'T SEND TECHNICAL QUESTIONS DIRECTLY TO ME, post them to newsgroups.
Don't bother cc'ing followups to me.

Vassil Nikolov

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to
David Gadbois wrote:
>
> Is ((LAMBA (FOO FOO) FOO) 1 2) legal ANS Common Lisp? The HyperSpec
> does not appear to have an answer.
(...)

From the HyperSpec:

3.1.1 Introduction to Environments
(...)
Bindings in an environment are partitioned into namespaces. A single
name can
simultaneously have more than one associated binding per environment,
but can
have only one associated binding per namespace.
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

HyperSpec---one of the best uses of disk space.

Good luck,
Vassil.

Rob Warnock

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to
David Gadbois <gad...@lagavulin.cyc.com> wrote:
+---------------

| Is ((LAMBA (FOO FOO) FOO) 1 2) legal ANS Common Lisp?
+---------------

FWIW (probably not much!), I thought I'd run it by a bunch of
Schemes, too, Scheme being so much about the Lambda Calculus and all: ;-}

These gave no error, and produced "1" as an answer:

SIOD
SCM
libscheme
SEL
RScheme

These gave no error, and produced "2" as an answer (as CLISP does):

TinyScheme
MiniScheme
Phantom
HPP
Scheme->C (the interpreter, might the compiler do better?)
Scsh [the Scheme Shell, based on Scheme-48]

These gave error messages (as CMUCL does):

Elk:
lambda: foo: duplicate variable binding

MzScheme:
let: multiple bindings of "foo" in: (#%let ((foo 1) (foo 2)) foo)

Gambit:
*** ERROR IN [compilation] -- Duplicate parameter in parameter list
(lambda (foo foo) foo)

Fools' Lisp:
Incorrect formal parameter redefinition of foo


-Rob

-----
Rob Warnock, 8L-855 rp...@sgi.com
Applied Networking http://reality.sgi.com/rpw3/
Silicon Graphics, Inc. Phone: 650-933-1673
2011 N. Shoreline Blvd. FAX: 650-964-0811
Mountain View, CA 94043 PP-ASEL-IA

Kent M Pitman

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to
As I reclal, and I could be wrong, repeated lambda variables were
explicitly forbidden in CLTL. I have a pretty definite and highly
elaborated memory of numerous discussions we had about possibly
changing that at X3J13. I don't think the proposed changes succeeded,
so I bet the wording forbidding them is in there somewhere. It could
be that it was the remark already cited by Vassil Nikolov regarding
number of associated bindings per namespace (which I agree is MOSTLY
sufficient), but I thought it said it in other places, too...

Even absent that, though, I always have to chuckle at people who
say things like "well, it's ok because it's not forbidden". Not to
make light of someone's good faith interpretation, but really:
semantics is more than saying syntax isn't forbidden--you have to say
what is meant. And a syntax that is not forbidden but that is assigned
no meaning can't really in any meaningful sense be permitted, unless
you want to quibble about programs like:

((lambda (x x) (declare (ignore x x)) 3) 4 5) => 3

and whether this is reasonable, because it's clear that

((lambda (x x) x) 3 4) => ?

might return either 3 or 4. Why? Well,

((lambda (&key x) x) :x 3 :x 4)

returns 3 [because that's well-defined] and so there's precedent
for assuming that the first binding applies, but this flies in the
face of what most would say is the OBVIOUS interpretation of

(let ((x 3)) (let* ((x (* 2 x)) (x (1+ x))) x))

which I think most people would say should yield 7. It's LET*
where I'd expect to find the wording just plain forbidding it,
and it was all over a fight that I personally found silly which
had two components. The first component was:

``We want a nice simple rule that everyone can understand.
The rule should be "no repeated variables" and should
not make "subtle" distinctions like binding contours.
It should refer to the textual shape of the code. So even
LET* can't take repeated variables.''

I fortunately don't remember who said this, but I'm prety
sure there were multiple people who did and they're welcome
to associate themselves with this compete put-down of the user
base if the want to. I and others advoated a rule based on
binding contours that said it was ok for LET* but not ok for LET.

The second component of the argument, which I can only hope was
really the basis of the other argument, and is what they meant
to say instead had to do with some legitimate issues that had
to be dealt with and that I would have simply dealt with by
definition, but that others felt were somehow something that if
we defined our way out of, we'd be admitting a wart in the
language that would somehow be omitted if we went with the
no repeated variables rule. (Personally, I saw complete symmetry
where you were just trading one set of problems for another and
I wanted the rule to be semantic, not syntactic.) Anyway,
the weird cases, if anyone cares, were things like:

(let ((x ...) (x ...)) (declare (string x)) ...)

You might think that this should aply to the inner binding,
but others felt it should apply to both bindings or that it
was at least confusing. Consider specifically:

(let* ((x 'foo) (x (symbol-name x)))
(declare (string x))
...)

In my view, if the person needs to declare something, you
could just ask him to separate them out, but I felt that
the inner binding only should be the obvious thing for it to
span. Again, I don't like the textual rule. Here's another
more subtle one.

(lambda (x x) (declare (string x)) ...)

Seems like the same problem, right? Well, not quite. They
are in the same contour and so this should be illegal, didn't
I advocate? Yeah, I did say that. But think about

(lambda (&optional x x) (declare (string x)) ...)

and even forget about the fact that the x defaults to nil.
We could make it

(lambda (&optional (x "foo") (x "foo")) (declare (string x))...)

if that mattered to you. But the thing you should be thinking about
instead of the stringness is the lack of parallel binding here.
Optionals are processed like LET*, not like LET, and for all you
know so are required variables. You think they're equivalent to
LET, but they're really not. &KEY and &AUX variables are also
left to right. Consider:

(lambda (&optional (x 'foo) (x (symbol-name x))) (declare (string x)) ...)

and you'll start to see the issue. Is it a reasonable conceptual
model to say that optionals and auxes are processed serially but requireds and
rests are processed in parallel... even when you know that there can't
be any way to prove whether the requires or rests are processed that way?
Plainly it's simpler to assume they are also serial, and then plainly
(if we can still call anything plain at this point),

(lambda (x x) (declare (string x x)) ...)

is like LET*, not like LET. But this then leaves us with a funny
rule that says that in

((lambda (x x &key (x x)) x) 1 2)

we should get 2 as the value since the rightmost binding should
dominate. But we already said we have defined

((lambda (x x &key (x x)) x) 1 2 :x 3 :x 4)

to return 3 rather than 4 because the leftmost actual arg dominates
in a keyword pickup situation (and there's good reason to think
this is the useful thing for reasons I won't go into, so dn't try
to say that decision was just an error).

We could make up some rule that says "rightmost vars, leftmost data"
and claim we meant it that way all along. (A careful study might
even show there was a deep reason why it has to work out that way and
we might just barely escape with a claim of a rational meaning.)

I wanted to just define that in the case of required lambda vars
or let bindings, you can't duplicate, and only in cases where you
have argument cascading can you do it. And I'd have compromised
down to saying that when there is a duplicated var, any declaration
needs to apply to both. but the other camp did have a reasonable
point on this second matter. So I think we just left things
deadlocked and preserved the CLTL wording.

But I hope I've at least put to rest the idea that if the spec
isn't 100% clear, that you can just decide that since it's not
forbidden it's ok.

It reminds me of that meeting (I think it was the Monterrey
meeting in early 1986) where Steele showed up with a couple of
pages of "trivial fixes" that he thought we'd all approve without
any question and was amazed and how many were controversial.
We learned right there that we had a hard road ahead.

-kmp

p.s. The reason I said Vassil's citation was only mostly
sufficient was because of this subtle issue of how
many bindings there are in LET* and in (lambda (x x) x).
Since a case can be made in both cases that there is
only one binding active at a time, then repetition
isn't forbidden under that rule. But I think there
is another rule somewhere to cover the exceptions.

David Gadbois

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to
Vassil Nikolov <vnik...@poboxes.com> writes:
> > Is ((LAMDBA (FOO FOO) FOO) 1 2) legal ANS Common Lisp? The

> > HyperSpec does not appear to have an answer.
>
> From the HyperSpec:
>
> 3.1.1 Introduction to Environments
> (...)
> Bindings in an environment are partitioned into namespaces. A
> single name can simultaneously have more than one associated
> binding per environment, but can have only one associated binding
> per namespace.

I would interpret the text as saying that relation NAME x ENVIRONMENT
x NAMESPACE x OBJECT is functional in OBJECT. However, it doesn't say
anything about shadowing, which is just the question at hand: Should
subsequent bindings of the same name in the same binding construct
shadow prior ones, or should it be an error. We certainly would not
want to rule out:

(let ((foo 1))
(let ((foo 2))
foo))


--David Gadbois

Lyman S. Taylor

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to
In article <w0kogob...@lagavulin.cyc.com>,
David Gadbois <gad...@lagavulin.cyc.com> wrote:
>Vassil Nikolov <vnik...@poboxes.com> writes:

>> Bindings in an environment are partitioned into namespaces. A
>> single name can simultaneously have more than one associated
>> binding per environment, but can have only one associated binding
>> per namespace.
>
>I would interpret the text as saying that relation NAME x ENVIRONMENT
>x NAMESPACE x OBJECT is functional in OBJECT.

I don't think the above disallows either. The nonoptional
arguments can be thought of as bound in parallel (as with LET).
When there are two (or more ) identical names and both must be bound
in parallel some sort of serialization must occur (especailly on
uniprocessors machines. ;-) ). That serialization
is implementation dependent. Therefore, you shouldn't write code
that depends upon this.

[ By the way, I now recall a "bug" report I once submited to
Harlequin for Lispworks. The interpreter and compiler
serialized the bindings for "redundant" LET names in
different orders. So it wasn't even consistant in the
same implementation. ]

Personally, I'd at least always issue a warning if not make
it an error. However, it takes "time" to check for such
dubious code. I don't think there is a inherently "correct"
interpretation of this kind of code.


>shadow prior ones, or should it be an error. We certainly would not
>want to rule out:
>
> (let ((foo 1))
> (let ((foo 2))
> foo))

Errr, each LET above defines a new environment. So there is no
conflict above.

The problem is how to you serialize parallel bindings. If you
mandate a serialization then the bindings are NOT parallel.

I don't think this sort of encoding has any "utility" so totally
diallowing is would be my vote. However, at time the lisp standards
don't make the implementations work as hard as they should.


P.S. the optional argument can have default values which depend upon the
value of a "previous" (in left to right order) argument. The
nonoptional args don't quite fit in this category.


--

Lyman S. Taylor "Twinkie Cream; food of the Gods"
(ly...@cc.gatech.edu) Jarod, "The Pretender"


Vassil Nikolov

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to
David Gadbois wrote:
>
> Vassil Nikolov <vnik...@poboxes.com> writes:
> > > Is ((LAMDBA (FOO FOO) FOO) 1 2) legal ANS Common Lisp? The
> > > HyperSpec does not appear to have an answer.
> >
> > From the HyperSpec:
> >
> > 3.1.1 Introduction to Environments
> > (...)
> > Bindings in an environment are partitioned into namespaces. A
> > single name can simultaneously have more than one associated
> > binding per environment, but can have only one associated binding
> > per namespace.
>
> I would interpret the text as saying that relation NAME x ENVIRONMENT
> x NAMESPACE x OBJECT is functional in OBJECT. However, it doesn't say
> anything about shadowing, which is just the question at hand: Should
> subsequent bindings of the same name in the same binding construct
> shadow prior ones, or should it be an error.

From the HyperSpec:

3.1.3 Lambda Expressions

In a lambda expression, the body is evaluated in a lexical
environment that is formed by adding the binding of each parameter
in the lambda list with the corresponding value from the arguments
to the current lexical environment.

I take this to mean that a lambda expression establishes a *single*
environment. Each parameter belongs to the same namespace, that of
variables. One environment, one namespace, therefore one binding.

Besides, the definition of shadowing implies that it takes *two*
forms to have shadowing.

--

Vassil Nikolov <vnik...@poboxes.com>
(You may want to cc your posting to me if I have to see it.)
LEGEMANVALEMFVTVTVM

Barry Margolin

unread,
Jan 7, 1999, 3:00:00 AM1/7/99
to
In article <369520...@poboxes.com>,

Vassil Nikolov <vnik...@poboxes.com> wrote:
>From the HyperSpec:
>
> 3.1.3 Lambda Expressions
>
> In a lambda expression, the body is evaluated in a lexical
> environment that is formed by adding the binding of each parameter
> in the lambda list with the corresponding value from the arguments
> to the current lexical environment.
>
>I take this to mean that a lambda expression establishes a *single*
>environment. Each parameter belongs to the same namespace, that of
>variables. One environment, one namespace, therefore one binding.

That quote is describing the environment in which the body is evaluated.
However, the fact that initializers for non-required parameters are allowed
to reference parameter variables that precede them in the lambda list
implies that there may be environments intermediate between the one outside
the lambda expression and the one in which the body is evaluated.

vnik...@poboxes.com

unread,
Jan 8, 1999, 3:00:00 AM1/8/99
to vnik...@poboxes.com
Barry Margolin wrote:
>
> In article <369520...@poboxes.com>,
> Vassil Nikolov <vnik...@poboxes.com> wrote:
> >From the HyperSpec:
> >
> > 3.1.3 Lambda Expressions
> >
> > In a lambda expression, the body is evaluated in a lexical
> > environment that is formed by adding the binding of each parameter
> > in the lambda list with the corresponding value from the arguments
> > to the current lexical environment.
> >
> >I take this to mean that a lambda expression establishes a *single*
> >environment. Each parameter belongs to the same namespace, that of
> >variables. One environment, one namespace, therefore one binding.
>
> That quote is describing the environment in which the body is evaluated.
> However, the fact that initializers for non-required parameters are allowed
> to reference parameter variables that precede them in the lambda list
> implies that there may be environments intermediate between the one outside
> the lambda expression and the one in which the body is evaluated.

I agree (or at least can't think of an objection) that there may be
intermediate environments (whose existence is, I suppose,
implementation dependent).

The original posting, however, was concerned with the evaluation of
the _body_: ((LAMBDA (X X) X) 1 2) ==> ? (And in the absence of
non-required parameters.)

May I add that there are (at least) two issues here:

(1) Could we imagine a reasonable Lisp where a lambda list such
as (X X) would be legal?

(2) Can it be definitely deduced from the ANSI Common Lisp standard
that a lambda list such as (X X) is illegal?

Note: I am not suggesting that anybody in their right mind
should be allowed to write lambda lists like that.
There could be contorted situations, however, where
such a lambda list might be constructed through the
programmatic combination of two or more lists (like
the situations where two occurences of the same
keyword parameter may come up in a function call
when argument lists are appended together).

As an aside, I find I have forgotten my lambda calculus studies
and can't decide if Lxx.x is well-formed (L stands for lambda).

Maybe this whole issue is not _that_ important, but if I recall
correctly, the definitions of languages such as C and Pascal
_explicitly_ forbid the presence of two different variables
with the same name in the same scope.

Have a nice day,
Vassil.

--

Vassil Nikolov <vnik...@poboxes.com>
(You may want to cc your posting to me if I have to see it.)
LEGEMANVALEMFVTVTVM

-----------== Posted via Deja News, The Discussion Network ==----------
http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own

Stig Hemmer

unread,
Jan 8, 1999, 3:00:00 AM1/8/99
to
vnik...@poboxes.com writes:
> As an aside, I find I have forgotten my lambda calculus studies
> and can't decide if Lxx.x is well-formed (L stands for lambda).

In the Lambda calculus we studied, each lambda only took one argument.

We quickly defined a convenience notation that allowed several
arguments, but it was only as a shorthand for nested one-argument
lambdas.

So, Lxx.x would be short for (Lx(Lx.x)), a perfectly legal expression.
Applied on any argument, it would return the identity function (Lx.x)
since the inner lambda protects its x's from being substituted. (I
have forget the usual terms for this. Something about free variables)

In Lisp terms, (lambda (x x) x) would return its second argument if
doing things the same way as the lambda calculus _we_ learned.

On the other hand, I know there are other lambda calculi, they might
do things differently.

Stig Hemmer,
Jack of a Few Trades.

Lieven Marchand

unread,
Jan 8, 1999, 3:00:00 AM1/8/99
to
Kent M Pitman <pit...@world.std.com> writes:
[lots of thoughtfull commentary snipped]

> I wanted the rule to be semantic, not syntactic.) Anyway,
> the weird cases, if anyone cares, were things like:
>
> (let ((x ...) (x ...)) (declare (string x)) ...)
>
> You might think that this should aply to the inner binding,
> but others felt it should apply to both bindings or that it
> was at least confusing. Consider specifically:

How does this interact with special?

Consider


(let ((x ...) (x ...))

(declare (special x) (string x)))

If we take your idea of allowing this for let* such a special
declaration could fold parts of your contour. Anyways, I fail to see
the utility of allowing duplication.

--
Lieven Marchand <m...@bewoner.dma.be>
------------------------------------------------------------------------------
Few people have a talent for constructive laziness. -- Lazarus Long

vnik...@poboxes.com

unread,
Jan 9, 1999, 3:00:00 AM1/9/99
to

I have received a private message about Lxx.x (I use L for
lambda, maybe others would find another ASCII character more
appropriate), and there has also been a posting. I could have
figured it out myself... Anyway, as it has been shown, we have:

(Lxx.x)12 === (Lx.(Lx.x))12 -> (Lx.x)2 -> 2

(and also Lxx.x === Lxy.y)

which taken literally means that

((lambda (x x) x) 1 2) should=> 2

and that bindings in a lambda expression should be treated
as in a LET* form and not LET.

This doesn't look quite reasonable to me especially that
in Lisp

(lambda (x y) ...) =/= (lambda (x) (lambda (y) ...))

although it beats me if this is merely a syntactic difference.

(I am also rather curious about what McCarthy would say about
this.)

Have a nice day or night,
Vassil.

Christopher R. Barry

unread,
Jan 9, 1999, 3:00:00 AM1/9/99
to

vnik...@poboxes.com writes:

> I have received a private message about Lxx.x (I use L for
> lambda, maybe others would find another ASCII character more
> appropriate), and there has also been a posting. I could have
> figured it out myself... Anyway, as it has been shown, we have:
>
> (Lxx.x)12 === (Lx.(Lx.x))12 -> (Lx.x)2 -> 2
>
> (and also Lxx.x === Lxy.y)
>

> which taken literally means that
>
> ((lambda (x x) x) 1 2) should=> 2

Under Allegro CL

USER(34): ((lambda (x x) x) 1 2)
2

CMUCL complaigns "Error: Repeated variable in lambda-list: X."

Lieven Marchand <m...@bewoner.dma.be> writes:

> Kent M Pitman <pit...@world.std.com> writes:
> [lots of thoughtfull commentary snipped]

> > I wanted the rule to be semantic, not syntactic.) Anyway,
> > the weird cases, if anyone cares, were things like:
> >
> > (let ((x ...) (x ...)) (declare (string x)) ...)
> >
> > You might think that this should aply to the inner binding,
> > but others felt it should apply to both bindings or that it
> > was at least confusing. Consider specifically:
>

> How does this interact with special?
>
> Consider

> (let ((x ...) (x ...))

> (declare (special x) (string x)))
>
> If we take your idea of allowing this for let* such a special
> declaration could fold parts of your contour. Anyways, I fail to see
> the utility of allowing duplication.

Under Allegro CL

USER(35): (let ((x 1) (x 2)) x)
1
USER(36): (let ((x "foo") (x "bar"))


(declare (special x) (string x)))

NIL

Dwight Hughes

unread,
Jan 9, 1999, 3:00:00 AM1/9/99
to
((lambda (x x) x) 1 2) returns 2 in Corman Common Lisp 1.11 and
Harlequin LispWorks for Windows 4.1 also

-- Dwight

Kent M Pitman

unread,
Jan 10, 1999, 3:00:00 AM1/10/99
to
Lieven Marchand <m...@bewoner.dma.be> writes:

> Kent M Pitman <pit...@world.std.com> writes:
> [lots of thoughtfull commentary snipped]

> > I wanted the rule to be semantic, not syntactic.) Anyway,
> > the weird cases, if anyone cares, were things like:
> >
> > (let ((x ...) (x ...)) (declare (string x)) ...)
> >
> > You might think that this should aply to the inner binding,
> > but others felt it should apply to both bindings or that it
> > was at least confusing. Consider specifically:
>

> How does this interact with special?

The question is not relevant unless you, like me, are speaking of
hypothetical universes. I opened by saying that this is illegal.
All of my discussion was about possible universes that Common Lisp
could have been, but isn't. I was trying to illustrate how the
language design might have come to the point that it is.


> Consider


> (let ((x ...) (x ...))

> (declare (special x) (string x)))
>
> If we take your idea of allowing this for let* such a special
> declaration could fold parts of your contour. Anyways, I fail to see
> the utility of allowing duplication.

I was not making an argument for duplication. I was surveying the
set of clues that might lead you to one point or the other. When
designing a language, there are many ways to go. It's more important
to be internally consistent than globally correct, since there is
no uniquely determined canonical sense of correct absent a set of
initial premises. If you go back and re-read my original note, you'll
see I was talking about things people had suggested that had been
discarded. My point was that LET* might be given a meaning. In the
case of LET*, if you did:
(let* ((x 'foo) (x (string x)))
(declare (special x) (string x)) ...)
I'd prefer a semantics in which this meant:
(let ((x 'foo))
(let ((x (string x)))
(declare (special x) (string x))
...)))
But not enough people in the committee agreed with me, so it didn't
end up meaning this.

Kent M Pitman

unread,
Jan 10, 1999, 3:00:00 AM1/10/99
to
cba...@2xtreme.net (Christopher R. Barry) writes:

> > ((lambda (x x) x) 1 2) should=> 2
>
> Under Allegro CL
>
> USER(34): ((lambda (x x) x) 1 2)
> 2
>

> CMUCL complaigns "Error: Repeated variable in lambda-list: X."

The subject line for this discussion seems misleading to me. This
form is not defined by CL. One cannot "grok" something that has no
meaning. You might have meant to say "Allegro happens, perhaps by
coincidence or luck, not to enter the debugger". ;-)

It looks to me, basd on my understanding, that Allegro's behavior as
you have described it is conforming, but only because when you do
something that is not defined, an implementation is not constrained to
do anything in particular, and therefore pretty much any behavior
would be conforming.

IMO, it is a bad idea to go around checking to see what
implementations do in illegal cases for any other purpose than to
lobby for change in the language. Also IMO, it is a VERY BAD idea to
think that observing a certain undocumented behavior is a promise that
the undocumented behavior will persist.

Unless you see in the Allegro doc that it INTENDS to return a certain
value in this case, you should avoid doing it. Partly because the
behavior isn't portable and partly because it might change without
warning even in the same implementation.

Ditto for CMUCL, btw, though it may not be so obvious to you since you
might expect that the error-signalling behavior is somehow more
principled and stable; that is: You should not assume it will signal
an error unless the doc says it will. Just as nothing prevents
Allegro from signalling an error here, nothing prevents CMUCL from
suddenly and without warning returning either 1 or 2 (or 173, for that
matter) in this case.


Marco Antoniotti

unread,
Jan 10, 1999, 3:00:00 AM1/10/99
to

Kent M Pitman <pit...@world.std.com> writes:

I agree with KMP. Moreover, I have the following doubt. In CMUCL it
turns out that

* ((lambda (x) (1+ x)) 3)
4

However, this is puzzling to me. I believe that this is a side effect
of having introduced the LAMBDA macro (therefore punishing me for my
previous comments on it introduction in ANSI CL :) ), but I would
have expected the above form to signal an error.

Any enlightening comments on the matter? Am I missing something from
the specification?

Cheers

Marco

--
Marco Antoniotti ===========================================
PARADES, Via San Pantaleo 66, I-00186 Rome, ITALY
tel. +39 - (0)6 - 68 10 03 17, fax. +39 - (0)6 - 68 80 79 26
http://www.parades.rm.cnr.it

Erik Naggum

unread,
Jan 10, 1999, 3:00:00 AM1/10/99
to
* Marco Antoniotti <mar...@copernico.parades.rm.cnr.it>

| Moreover, I have the following doubt. In CMUCL it turns out that
|
| * ((lambda (x) (1+ x)) 3)
| 4
|
| However, this is puzzling to me.

this has been meaningful since CLtL1 and way before then. it's called a
`lambda form' in the standard.

lambda form n. a form that is a list and that has a first element which is
a lambda expression representing a function to be called on arguments which
are the result of evaluating subsequent elements of the lambda form.

3.1.2.1.2.4 Lambda Forms reads:

A lambda form is similar to a function form, except that the function name
is replaced by a lambda expression.

A lambda form is equivalent to using funcall of a lexical closure of the
lambda expression on the given arguments. (In practice, some compilers are
more likely to produce inline code for a lambda form than for an arbitrary
named function that has been declared inline; however, such a difference is
not semantic.)

http://www.harlequin.com/books/HyperSpec/Body/sym_lambda.html has the
specification of the symbol LAMBDA.

| Any enlightening comments on the matter? Am I missing something from
| the specification?

not any more. :)

#:Erik

Kent M Pitman

unread,
Jan 10, 1999, 3:00:00 AM1/10/99
to
Erik Naggum <er...@naggum.no> writes:

> * Marco Antoniotti <mar...@copernico.parades.rm.cnr.it>
> | Moreover, I have the following doubt. In CMUCL it turns out that
> | * ((lambda (x) (1+ x)) 3)
> | 4
> | However, this is puzzling to me.
>
> this has been meaningful since CLtL1 and way before then. it's called a
> `lambda form' in the standard.

Right. It's called a lambda combination in the traditional literature
but the name didn't seem consistent with "function form" which I was
already using, so I took some liberties with terminology.

But this has been a standard thing ever since Lisp began, and in fact
was an argument against introducing the lambda macro--that it would
confuse people into thinking any form could go in the car of a form
(a la Scheme) if we allowed even one "apparent form" to go there.
Traditionally, (lambda ...) has been the only compound form which was
permitted to be feval'd (eval'd in the function namespace). In a
literal sense, the LAMBDA macro is a translator from the variable namespace
to the funciton namespace because it turns
(lambda (x) x) => (function (lambda (x) x))
In other words, it requests that the form apparently in the variable
namespace be evaluated in the function namespace. But it does this
only when you put it in a variable namespace position, as in:
(funcall (lambda (x) x) 3)
which is equivalent to
(funcall (function (lambda (x) x)) 3)
because the argument to funcall is evaluated in the variable namespace
and consequently is macroexpanded. The car of a form is the functional
position and is not evaluated in the variable namespace. In
(f x)
the F is evaluated as (function F) not as just F, and consequently
it is also not macroexpanded. So when you see
((lambda (x) x) 3)
you are NOT seeing something equivalent to
((function (lambda (x) x)) 3)
because macroexpansion does not occur in the car. Conceptually, the
motivation for this is that
((function f) x)

Symbolics Lisp (and maybe all Lisp Machine Lisp dialects, I don't
remember and am too lazy to look) offers define-lambda-macro which
specifically allows you to define the meaning of a name L in an
expression ((L ...) ...) or (function (L ...)). Effectively, it's
what I would have called an "fmacro" (a macro on compound forms in the
function namespace) since the convention in history has been to prepend
"f" to things that operate on the function namespace [there having been
many operations like FBOUNDP, FEVAL, FDEFINE, etc. in varying
dialects--FBOUNDP showing itself in Common Lisp]. The purpose of
lambda macros in Symbolics Lisp is to support the definition of
things like Interlisp NLAMBDA, which implicitly quoted all of its
args such that ((nlambda (x y z) (list x y z)) a b c) => (A B C)
In the Lisp Machine's Zetalisp dialect (in which the system is written;
keep in mind Lisp Machines have numerous co-resident dialects in the
same address space), you'd say
((lambda (&quote x y z) (list x y z)) a b c)
and in fact Zetalisp is general enough that you can also do:
(let ((c 3))
((lambda (&quote x y &eval z) (list x y z)) a b c))
=> (A B 3)
Lambda macros could have also been used, though I never saw it done,
to define things like an "identity" function, such that
(function (eql 17))
might turn into
(function (lambda (&rest x) (declare (ignore x)) (quote 17)))
That is, they could be general-purpose macros in a different namespace
(not interfering with the meaning of functions in the variable
namespace). I proposed the introduction of lambda macros into CL,
but no one liked it and it never happened.

See my web-annotated paper
http://world.std.com/~pitman/Papers/Special-Forms.html
for why I think &quote and NLAMBDA and related operators (collectively
called FEXPRs in Maclisp parlance) were bad ideas. They fell really
sharply off into almost total disuse shortly after the paper--though
I've never been sure if it was because of the paper or only because it
was an idea whose time had come and I was just coincidentally writing
about it for the same reason.

Oh, one more thing about LAMBDA. When I first started using Lisp, there
was a macro capability in Maclisp, but it was virtually unused by the
system. Many people "invented" LET and the variety of implementations
was fascinating, but it was a common step in learning Lisp that someone
eventually introduced you to LET by assuring you that
(let ((x 3)) x)
was the same as the "familiar"
((lambda (x) x) 3)
It's an interesting commentary on the changing times that not only is
a "lambda combination" or "lambda form" not something that's most
common, but it is so unused that many users now don't even know about
it. I recall long ago (circa 1978) meeting Al Rich, implementor of
Mulisp, and having him show me his homemade Lisp. (The story of how
that Lisp got created is an amazing story I'll leave him to tell
himself on another occasion--but let me say I have great respect for
it as an alternate branch in the Lisp tree, even though it's not the
branch I've participated in and tracked. Don't take my comments here
as disparaging.) Anyway, because he developed his Lisp in a isolation
of most other influences, he apparently had never noticed the
existence of lambda combinations in his reading, and his Lisp didn't
have it. Moreover, he had a conditional shorthand that let you write
((foo x) y)
which was shorthand for
(cond ((foo x) y))
because he didn't think ((anything ...) ...) was ever used and he
thought that was a waste. I kept writing ((lambda ...) ...) as I was
testing my little toy app in his lisp and it didn't work. He was as
baffled by what I was writing as I was about the behavior. It took us
a while to realize the problem, because it was inconceivable to me at
the time that someone would NOT know what a Lambda combination was.
At the time, it was one of the critical and most central things about
Lisp. What was the point of this story? I don't know. Just that
it's funny how expectations change over time, I guess. Today, Al
Rich's decision to sacrifice lambda combinations in favor of a
conditional shorthand might be defensible as "ground-breaking" for
getting rid of a useless appendage. (Maybe it always was and I just
didn't see it as such at the time.) That's why I keep saying over and
over that design decisions are never right or wrong in the
absolute--they only have goodness or badness in a well-understood
context.

vnik...@poboxes.com

unread,
Jan 10, 1999, 3:00:00 AM1/10/99
to
In article <sfw4spz...@world.std.com>,
Kent M Pitman <pit...@world.std.com> wrote:
(...)

> but it was a common step in learning Lisp that someone
> eventually introduced you to LET by assuring you that
> (let ((x 3)) x)
> was the same as the "familiar"
> ((lambda (x) x) 3)

It was a little revelation to me when, about 10 years ago, I was
examining how Sun (i.e. Lucid) Common Lisp 3.0 did various things
and saw that (LET ...) expanded into ((LAMBDA ...) ...). I knew
about lambda forms, but it had never occurred to me that LET
could be done on top of them. (This also helped me understand
that CLtL1 rule about the scope of declarations in LET not
including the initialisers.)

Have a nice day or night,
Vassil.


Vassil Nikolov <vnik...@poboxes.com> www.poboxes.com/vnikolov
(You may want to cc your posting to me if I _have_ to see it.)
LEGEMANVALEMFVTVTVM (Ancient Roman programmers' adage.)

Howard R. Stearns

unread,
Jan 12, 1999, 3:00:00 AM1/12/99
to
I always wondered about:

(defun foo (...)
...)
(defun (setf foo) (val ...)
...)

(funcall #'foo ...) ;ok
(funcall #'(setf foo) x ...) ;ok

(funcall 'foo ..) ;ok
(funcall '(setf foo) x ..) ;ok

(foo ...) ;ok
((setf foo) x ...) ;Not specifically permitted in ANSI CL

In fact, if I recall correctly, the first subform of a combination must
explicitly be
of type SYMBOL or (CONS (EQL LAMBDA)). I might (naively?) have
otherwise assumed that the first subform must be an
EXTENDED-FUNCTION-NAME, or something similar, where
EXTENDED-FUNCTION-NAME (or whatever) is defined in such a way that it
does not preclude special-operators or macro names.

Kent M Pitman

unread,
Jan 13, 1999, 3:00:00 AM1/13/99
to
"Howard R. Stearns" <how...@elwood.com> writes:

> I always wondered about:
>
> (defun foo (...)
> ...)
> (defun (setf foo) (val ...)
> ...)
>
> (funcall #'foo ...) ;ok
> (funcall #'(setf foo) x ...) ;ok
>
> (funcall 'foo ..) ;ok
> (funcall '(setf foo) x ..) ;ok
>
> (foo ...) ;ok
> ((setf foo) x ...) ;Not specifically permitted in ANSI CL

I remember discussing this but not the specific positions taken (nor
even my own). Almost surely someone would have raised the issue that
there was no "current practice" nor "compelling need". Some others
may also have worried that SETF was already pretty complicated to
understand and that this would only make things worse... I think by
sorta making it look like a schemish (<form> ...) was allowed. You
see, ((lambda...) ...) had traditionally been allowed, but if it had
to be announced now, I bet it would probably be voted down for same
reason. But at least it isn't confusing in that its meaning and
syntax is the same in the car of the form as elsewhere, whereas SETF
in the car position would mean something different than elsewhere. In
the end, it was ad hoc and everyone knew it, and people were probably
so focused on damage control that they didn't look at the bigger
picture. Just combining speculation with vague fragments of memory
and trying to piece it back together. Not very reliable from a
historical point of view. Mostly I agree with what I think you're
saying, though, that this kind of generalization (to allow a setf name
in the car of a form) for the sake of simpler naming is a good idea.
I'll hunt around and see if I can find a specific record of the
issues.

> In fact, if I recall correctly, the first subform of a combination must
> explicitly be
> of type SYMBOL or (CONS (EQL LAMBDA)). I might (naively?) have
> otherwise assumed that the first subform must be an
> EXTENDED-FUNCTION-NAME, or something similar, where
> EXTENDED-FUNCTION-NAME (or whatever) is defined in such a way that it
> does not preclude special-operators or macro names.

Yeah...

0 new messages