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.
In article <w0ksodoian6....@lagavulin.cyc.com>, David Gadbois <gadb...@lagavulin.cyc.com> wrote: > 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
MCL says:
> Error: While compiling an anonymous function : > Bad lambda list : (FOO FOO)
In article <w0ksodoian6....@lagavulin.cyc.com>, David Gadbois <gadb...@lagavulin.cyc.com> wrote: > 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
MCL says:
> Error: While compiling an anonymous function : > Bad lambda list : (FOO FOO)
In article <770jgj$...@pravda.cc.gatech.edu>, Lyman S. Taylor <ly...@cc.gatech.edu> wrote:
>In article <w0ksodoian6....@lagavulin.cyc.com>, >David Gadbois <gadb...@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.
> 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. ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
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:
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:
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
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:
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.
Vassil Nikolov <vniko...@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:
In article <w0kogobhtep....@lagavulin.cyc.com>, David Gadbois <gadb...@lagavulin.cyc.com> wrote:
>Vassil Nikolov <vniko...@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 <vniko...@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 <vniko...@poboxes.com> (You may want to cc your posting to me if I have to see it.) LEGEMANVALEMFVTVTVM
In article <369520FE.1...@poboxes.com>, Vassil Nikolov <vniko...@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.
-- 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.
> In article <369520FE.1...@poboxes.com>, > Vassil Nikolov <vniko...@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 <vniko...@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
vniko...@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.
> 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:
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
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
vniko...@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:
> > 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:
> 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 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:
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:
> > 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.
> 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.
> 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.
> 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.
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?
* Marco Antoniotti <marc...@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.)
Erik Naggum <e...@naggum.no> writes: > * Marco Antoniotti <marc...@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 ("e 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 ("e 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 "e 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.
In article <sfw4spz9i7g....@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 <vniko...@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.)
-----------== Posted via Deja News, The Discussion Network ==---------- http://www.dejanews.com/ Search, Read, Discuss, or Start Your Own
(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.