In article <m3r87loheb....@javamonkey.com>, Peter Seibel
<pe...@javamonkey.com> wrote:...a whole bunch of good points.
Thanks, it is going to take a while for all this to sink in.
BTW, thanks for your second follow-up post clarifying some points you brought up in your first post, all that helps considerably in getting me to understand the various subtle aspects of this issue.
In article <slrnbaseub.on.Gareth.McCaug...@g.local>, Gareth McCaughan
<Gareth.McCaug...@pobox.com> wrote: > > x is obviously a lexically scoped variable, because if we change its > > value then there is no effect on our closure function "test"
> No, X is not a lexically scoped variable. X is a special kind > of macro. I don't think it's unreasonable, though, to say > that the definition of this macro is part of a "top-level > lexical environment". But there is no top-level lexical > environment *for variables*.
Yipes!, my head hurts.<g>
Give me a little time to let this all sink in.
> Consider:
> (define-symbol-macro x (list 1 2 3)) > (eql x x) ==> NIL
> This is not good.
Definitely not good, I agree. It is very hard to determine if the first-x above is retrieved from the same memory location as the second-x was retrieved from, considering that a lot of macro expansion is going on behind-the-scenes.
> > (define-symbol-macro x (list 1 2 3)) > > (eql x x) ==> NIL
> > This is not good.
> Definitely not good, I agree. It is very hard to determine if the > first-x above is retrieved from the same memory location as the > second-x was retrieved from, considering that a lot of macro expansion > is going on behind-the-scenes.
What (define-symbol-macro x <something>) means is: textually substitute <something> for X every time it appears. (Well, almost. That doesn't happen in quoted data, and it doesn't happen when X is in function position.)
So, after (define-symbol-macro x (list 1 2 3)), there is no difference at all between (eql x x) and (eql (list 1 2 3) (list 1 2 3)). And LIST is guaranteed to cons up a fresh list each time you call it.
-- Gareth McCaughan Gareth.McCaug...@pobox.com .sig under construc
What (list ...) returns is the address in memory of a freshly-consed Lisp list. This is known as "returning a list". As a previous poster said, (list ...) always conses up a fresh list. (The objects contained in the list needn't be fresh but the conses in the list are fresh; the fresh conses can point to old, previously-existing objects.) A Lisp list is a series of cons cells with the car of the cons containing the list entry and the cdr of the cons pointing to the next cons in the list. That's why a and c are "the same" below. Both a and c are variables bound to the same cons cell, which is the first one in the list. (Note: I never hear Lisp people talk about "point to". a is not a variable, it is a symbol. It may be correct to say the symbol is bound to the list. If that is not a correct phrasing, I expect quickly to be corrected.)
But there's a misuse in my code. I'm using eq, not eql. a and c always will be eq - the object referred to is the same both for a and c. Think of eq as comparing memory addresses, that is, eq asks if the two parameters reside at the same memory address. (Implementations are allowed to treat chars and numbers differently with eq. See below for more.) Although in this example the (car a) or (car b) comparisons show eq returning T, and many implementations may do so, that is not a requirement. It's worse than that. It's back to the undefined behavior discussions you've been through recently.
Look at eq in the hyperspec. eq may or may not return T when given "the same" haracters and numbers. I included eq's here just to let you know that you should use eq when comparing things like a and c, eql when comparing numbers and characters, equal when comparing larger structures such as lists (conses) or arrays (strings and bit-vectors are compared element by element using eql). equalp is like equal except ignoring case. eq may appear to work when comparing characters and numbers but it is not guaranteed to work for that purpose.
It's easiest for beginners to use eql except when comparing strings, when it is good to use equal (or equalp for case insensitivity). (I think I have that part right.)
(By the way, in the Lisp implementation I'm using, the following code gave the same result when I used eql instead of eq.)
CL-USER 18 > (let* ((a (list 1 2 3)) (b (list 1 2 3)) (c a)) (format t "~&1: ~a ~a eq?:~a" a b (eq a b)) (format t "~&2: ~a ~a eq?:~a" (car a) (car b) (eq (car a) (car b)))
(format t "~&3: ~a ~a eq?:~a" a c (eq a c)) (rplaca a 4) ;; replace the car of 'a' with '4' (format t "~&4: ~a ~a eq?:~a" a b (eq a b)) (format t "~&5: ~a ~a eq?:~a" (car a) (car b) (eq (car a) (car b))) (format t "~&6: ~a ~a eq?:~a" a c (eq a c)))
In the example below, x is a define-symbol-macro, which means that x is replaced by (list 1 2 3) wherever x appears. x appears twice in (eql x x). Therefore it is the same as (eql (list 1 2 3) (list 1 2 3)), which is the same as a and b in my example above. Each invocation of list created a fresh set of conses, the addresses in memory of which are different. (eql x x) ==> NIL means that the two lists are not the same list, the leading cons cells are not at the same memory address. Compare that to my example #3 above, where a and c are the same list and (eql a c) ==> T. a and c are symbols bound to the same variable, the same cons cell, the same address in memory.
>> (define-symbol-macro x (list 1 2 3)) >> (eql x x) ==> NIL
>>This is not good.
> Definitely not good, I agree. It is very hard to determine if the > first-x above is retrieved from the same memory location as the > second-x was retrieved from, considering that a lot of macro expansion > is going on behind-the-scenes.
> It's easiest for beginners to use eql except when comparing strings, > when it is good to use equal (or equalp for case insensitivity).
Wouldn't the best newbie advice be just use EQUAL until they start to care about the subtle differences?
I tend to use equal for everything unless I want the added code documentary benefits of = (means this is math), string= -equal or -equalp (means we are using only strings), eq (means I am using symbols) and char= (means I know these are characters)
Whenever things might be mixed and I don;t want an error (most often NIL can slip in) it's back to EQUAL. (YMMV, IMHO, etc etc...)
> > It's easiest for beginners to use eql except when comparing > > strings, when it is good to use equal (or equalp for case > > insensitivity).
> Wouldn't the best newbie advice be just use EQUAL until they start > to care about the subtle differences?
I think they should be taught about objects and object identity right from start, and consequently use EQL. If they discover along the way that sometimes strings that are STRING= are /not/ EQL and hence must be two different objects, they'll have learned something useful. If they use EQUAL all the time, however, they'll get bitten by FIND and CASE and all the other places where EQL is the default equality predicate. Also, how would you explain
CL-USER 11 > (equal '(a b c) '(a b c)) T
CL-USER 12 > (equal #(a b c) #(a b c)) NIL
to them, if you had told them just before that EQUAL was the generic equality predicate?
Object identity is a fundamental notion; equality is not.
Regards, -- Nils Gösche "Don't ask for whom the <CTRL-G> tolls."
In article <m3r87loheb....@javamonkey.com>, Peter Seibel
<pe...@javamonkey.com> wrote: > > (defun test () x))
> > We know that running the closure function (test) will return 2
> This isn't a closure since X is not a variable. It's a macro. When you > evaluated the DEFUN form X was replaced with the literal 2, just as if > you had written:
> (defun test () 2)
I still think test is a closure. It does not matter much exactly *when* the literal 2 was slapped in there, as regards whether "test" is a closure.
The important thing about whether something is a closure or not is whether it preserves the prior state (value) of a variable when a lexical binding form like a "let" is trying to change that value.
Consider code below, where this time it is called test2 instead of test.
Forgive the sloppy code, I don't know how to use "format" yet.
(define-symbol-macro x 2)
(defun test2 () (terpri) (princ "\"test2\" is a closure because it preserves value of global x\,") (terpri) (princ "value of global x in this case is ") (princ x) (terpri))
(let ((y 3)) (defun test3 () (terpri) (princ "\"test3\" is also a closure\, made in the conventional way\,") (terpri) (princ "it preserves the value of ") (princ y) (terpri)))
(defun test4 (p) (terpri) (princ "\"test4\" is not a closure\, it preserves no prior value\,") (terpri) (princ "this time test4 prints ") (princ p) (terpri))
(let ((x 'boom) (y 'bam) (z 'fizzle)) x y (terpri) (test2) (terpri) (test3) (terpri) (test4 z) (terpri) (terpri) (terpri) (values))
Below is the screen printout from running the "let" form:
"test2" is a closure because it preserves value of global x, value of global x in this case is 2
"test3" is also a closure, made in the conventional way, it preserves the value of 3
"test4" is not a closure, it preserves no value, this time test4 prints FIZZLE
In article <slrnbatghf.on.Gareth.McCaug...@g.local>, Gareth McCaughan
<Gareth.McCaug...@pobox.com> wrote: > What (define-symbol-macro x <something>) means > is: textually substitute <something> for X > every time it appears. (Well, almost. That > doesn't happen in quoted data, and it doesn't > happen when X is in function position.)
I tried to imagine how I would get into trouble with the 'quoted' and the 'function-position' thingy, but drew a blank.
Is relying on "define-symbol-macro" going to get me into trouble down the road, in your estimation.
* Mark Conrad wrote: > I still think test is a closure. It does not matter much exactly > *when* the literal 2 was slapped in there, as regards whether "test" is > a closure. > The important thing about whether something is a closure or not is > whether it preserves the prior state (value) of a variable when a > lexical binding form like a "let" is trying to change that value.
No, that is not the important thing at all. The important thing is that a closure captures a *binding* of a variable to a value, which binding is mutable state. If the binding modified (so its value is changed) then all the closures which share that binding see the modified binding.
You *really* need to go away and do some serious reading, because you are making yourself look (no: you have made yourself look) a fool.
Tim Bradshaw <t...@cley.com> writes: > * Mark Conrad wrote:
> > I still think test is a closure. It does not matter much exactly > > *when* the literal 2 was slapped in there, as regards whether "test" is > > a closure.
> > The important thing about whether something is a closure or not is > > whether it preserves the prior state (value) of a variable when a > > lexical binding form like a "let" is trying to change that value.
> No, that is not the important thing at all. The important thing is > that a closure captures a *binding* of a variable to a value, which > binding is mutable state. If the binding modified (so its value is > changed) then all the closures which share that binding see the > modified binding.
The Elite ttlotbafir Greenspunian Guard recently invented lexical scoping with visibility but not mutation of variables from outer scopes. They call the obscenities resulting from passing these around "closures", and (so far, at least) they Won't Be Told.
> You *really* need to go away and do some serious reading, because you > are making yourself look (no: you have made yourself look) a fool.
Is there a rilly rilly big (and ideally authoritative, but mostly big) reference book I can beat them about the head with?
Des will then work on multiple name-spaces, macros and s-exp syntax. -- Des Small / Scientific Programmer/ School of Mathematics / University of Bristol / UK / Word falling / Image falling
Mark Conrad <nos...@iam.invalid> writes: > In article <slrnbatghf.on.Gareth.McCaug...@g.local>, Gareth McCaughan > <Gareth.McCaug...@pobox.com> wrote:
> > What (define-symbol-macro x <something>) means > > is: textually substitute <something> for X > > every time it appears. (Well, almost. That > > doesn't happen in quoted data, and it doesn't > > happen when X is in function position.)
> I tried to imagine how I would get into trouble with the 'quoted' > and the 'function-position' thingy, but drew a blank.
He meant, I imagine, that if you do this:
(define-symbol-macro x 2)
and then this:
(defun x () 10)
Lisp doesn't get confused when you say this:
(x) ==> 10
while:
x ==> 2
and
'(x) ==> (x)
That is, the macro is not expanded in contexts where it doesn't "look like" a variable. (As opposed to, say, C "macros" which really are textual substitution. Blech.)
> Is relying on "define-symbol-macro" going to get me into trouble down > the road, in your estimation.
I'd say yes. Until you get a deeper understanding of what macros, variables, closures, etc. actually are. I'd reiterate the point someone made a couple weeks ago--learn Lisp. Use it the way it was intended to be used. Get it under your fingers.
When you are an expert, you may figure out some clever hacks that you can build on top of symbol macros, but until then you mostly seem to be confusing yourself.
You really ought to consider starting back from the top--what's the problem you're trying to solve? I.e. if you're trying to write some software, what's it supposed to do? I imagine there are some folks here might be willing to help you figure out the idiomatic Lisp way of writing software that does whatever it is.
The intellectual level needed for system design is in general grossly underestimated. I am convinced more than ever that this type of work is very difficult and that every effort to do it with other than the best people is doomed to either failure or moderate success at enormous expense. --Edsger Dijkstra
Mark Conrad <nos...@iam.invalid> writes: > In article <m3r87loheb....@javamonkey.com>, Peter Seibel > <pe...@javamonkey.com> wrote:
> > > (defun test () x))
> > > We know that running the closure function (test) will return 2
> > This isn't a closure since X is not a variable. It's a macro. When you > > evaluated the DEFUN form X was replaced with the literal 2, just as if > > you had written:
> > (defun test () 2)
> I still think test is a closure.
Then you must think that there is a binding over which TEST is closed. But the function TEST does not refer to any bound variables. Therefore it is not a closure.
> It does not matter much exactly *when* the literal 2 was slapped in > there, as regards whether "test" is a closure.
Actually it does. Suppose I write this code:
(defun foo (x) (+ x 3))
Is this closed over anything? What if I told you that I was mentally thinking of a variable name, but I knew it would never change from 3, so I omitted it and just used the literal. Under your definition, FOO is closed over a variable, but you'd have to read my mind to find out which variable.
> The important thing about whether something is a closure or not is > whether it preserves the prior state (value) of a variable when a > lexical binding form like a "let" is trying to change that value.
No, because this would apply to copies as well. Consider:
This returns two values, only one of which (the first) is a closure. The closure can refer to the binding of X and can modify that binding. The second value returned is a function that `preserves the prior state (value)' of X, yet it is not a closure because it does not refer to the binding of x.
> > > What (define-symbol-macro x <something>) means > > > is: textually substitute <something> for X > > > every time it appears. (Well, almost. That > > > doesn't happen in quoted data, and it doesn't > > > happen when X is in function position.)
[Mark Conrad replied:]
> > I tried to imagine how I would get into trouble with the 'quoted' > > and the 'function-position' thingy, but drew a blank.
> > Is relying on "define-symbol-macro" going to get me into trouble down > > the road, in your estimation.
Depends what you mean. If you need something that behaves like a global lexical then you need to use define-symbol-macro, so relying on that is your only option.
But: Until you understand what define-symbol-macro is doing, using it is liable to get you into trouble; until you understand how variable bindings work in Lisp, just about everything is going to get you into trouble.
But the solution to this is to learn to understand, not to put define-symbol-macro in a box labelled "dangerous". Everything's dangerous until you understand it.
On the other hand, if you weren't determined that your first Lisp project *must* involve Paul Graham's continuation stuff, I'd suggest that you could pick better areas of Lisp to concentrate on for now...
-- Gareth McCaughan Gareth.McCaug...@pobox.com .sig under construc
In article <wuhaehv7....@ccs.neu.edu>, Joe Marshall <j...@ccs.neu.edu> wrote:
> Then you must think that there is a binding over which TEST is closed. > But the function TEST does not refer to any bound variables. > Therefore it is not a closure.
True, so far as your reasoning goes.
However, I maintain that a closure can "close-over" and preserve the value of "stuff" other than the bindings created by 'let' and its cousins.
Let's look at the temporary binding of x to the value 7 below:
(defun baz (x) "The parameter-variable x is 'bound' temporarily to whatever value is supplied to baz when baz is executed" (cons x '(is bound to x within the function baz)))
Now when baz is used below, the value 7 is temporarily "bound-to" the lexically-scoped variable x which resides in the definition of the function baz.
? (baz 7) (7 IS BOUND TO X WITHIN THE FUNCTION BAZ)
baz does not qualify as a closure bacause the binding of x is not preserved; that binding of x to value 7 is lost as soon as baz terminates.
Okay, with that out of the way, let's create two things, a real closure which we will name "closure", and a function that might be a closure, which we will name "closure???"
The aim of this exercise is to determine if both functions act the same under all circumstances of usage.
(define-symbol-macro k 'whoopie)
(defun closure??? () k)
(let ((h 'fe-fi-fo-fum)) (defun closure () h))
Now if "closure???" looks like a duck, sounds like a duck, and waddles like a duck, as far as I am concerned it is a duck.
So far, both "closure" and "closure???" both act alike, in the sense that they both preserve the values of whatever they were bound to at the time of their creation.
Yes, I accept the fact that k is not a variable, but rather a macro.
Despite that, to all intents and purposes k acts like a variable, does it not?
I imagine that if I pushed it too far, k would break my code just when I started relying on k to act like a variable.
In article <m3n0i6k8wz....@javamonkey.com>, Peter Seibel
<pe...@javamonkey.com> wrote: > > Is relying on "define-symbol-macro" going to get me into trouble down > > the road, in your estimation.
> I'd say yes. Until you get a deeper understanding of what macros, > variables, closures, etc. actually are. I'd reiterate the point > someone made a couple weeks ago--learn Lisp. Use it the way it was > intended to be used. Get it under your fingers.
So far as learning Lisp from books is concerned, I have not had any luck resolving issues like the ones we are discussing here.
In other words, there are things that can only be learned by asking specific questions in NG's like this one.
> You really ought to consider starting back from the top--what's the > problem you're trying to solve?
I am trying to learn how to use Paul Graham's macros to implement continuations in CL.
In order to do that, I have to learn enough about scope and extent issues peculiar to his macros.
The text and examples in his book do not go into sufficient detail about toplevel bindings and extent issues of his global variable "*cont*" in his book.
Specifically, my present 'learning-project' is to try to implement catch/throw using continuations only, i.e. to pretend that catch and throw do not exist in CL.
In article <ey3vfwuepjf....@cley.com>, Tim Bradshaw <t...@cley.com> wrote:
> You *really* need to go away and do some serious reading, because you > are making yourself look (no: you have made yourself look) a fool.
Reading does not resolve the issues being discussed here, and I have many darn good Lisp books.
I care less about appearing a fool, that does not bother me at all.
If I make foolish, wrong, convoluted, nonsense statements in this NG, the fine people here do not let those statements stand.
They correct me, and I learn.
...then I make another rash statement, based on my enlightened newer knowledge. If the newer statement is still incorrect, again I get corrected forthwith.
As I get closer and closer to the truth of the matter, eventually my statements make sense.
Mark Conrad <nos...@iam.invalid> writes: > In article <ey3vfwuepjf....@cley.com>, Tim Bradshaw <t...@cley.com> > wrote:
> > You *really* need to go away and do some serious reading, because you > > are making yourself look (no: you have made yourself look) a fool.
> Reading does not resolve the issues being discussed here, and I have > many darn good Lisp books.
> I care less about appearing a fool, that does not bother me at all.
> If I make foolish, wrong, convoluted, nonsense statements in this NG, > the fine people here do not let those statements stand.
> They correct me, and I learn.
The observed problem is that it takes multiple corrections of the same mistake on your part to pound the message home. Most people do not want to have to deal with this for free. The real issue is that you have not just appeared a fool but that you have made a good case for actually being a fool. You did this by repeatedly disregarding the corrections presented to you about the need for continuations in Common Lisp, you did not get the point until people, who generally do not insult people here, started insulting you because of your repeated refusal to engage your brain in the discussion.
> ...then I make another rash statement, based on my enlightened newer > knowledge. If the newer statement is still incorrect, again I get > corrected forthwith.
At least you know the difference between rash and ignorant
> As I get closer and closer to the truth of the matter, eventually my > statements make sense.
Mark Conrad wrote: > If I make foolish, wrong, convoluted, nonsense statements in this NG, > the fine people here do not let those statements stand.
> They correct me, and I learn.
> ...then I make another rash statement, based on my enlightened newer > knowledge. If the newer statement is still incorrect, again I get > corrected forthwith.
> As I get closer and closer to the truth of the matter, eventually my > statements make sense.
The danger is that, before your statements start to make sense, the fine people here decide that you're wasting their time. Because the approach you're taking is, shall we say, not calculated to minimize the number of foolish questions you need to ask. Some people may reasonably feel that they aren't obliged to offer you the extra support that's required as a result of your inefficient choice of learning method.
(I'm not as convinced as some people here that it's a very bad way to learn. There's something to be said for jumping in at the deep end, and there's a lot to be said for learning by doing something that motivates you. But you have to be aware that you're running the risk of annoying the people you depend on for help so much that they give up...)
-- Gareth McCaughan Gareth.McCaug...@pobox.com .sig under construc
Mark Conrad <nos...@iam.invalid> wrote: > Reading does not resolve the issues being discussed here, and I have > many darn good Lisp books.
Then you are reading the wrong books, or the right books in the wrong manner.
Several of your comments have demonstrated a general lack of rigor required to grasp the underlying issues. You have also on numerous occasions referred to "On Lisp", which could be considered an advanced text. Hence, I would recommend two books to you:
1) Structure and Interpretation of Computer Programs. The full text is available online, just google for it. Don't just read it, but do the excercises as well. And don't expect to finish it in "a week or two". Depending on the time you invest two months to a year is a more realistic goal.
After you have finished the SICP:
2) ANSI Common Lisp by Paul Graham. This one you have to buy, but it's worth it. If you have SICP under your belt at this point it will be fast and easy reading.
Then you can have a go at "On Lisp" and continuations. Sorry, but that's the way it is.
* Mark Conrad wrote: > Now if "closure???" looks like a duck, sounds like a duck, and waddles > like a duck, as far as I am concerned it is a duck.
But it doesn't, does it? Try this:
(let ((x 1)) (defun x () x) (defun set-x (new) (setf x new)))
(x) (set-x 3) (x)
Hey, look, mutable state!
As to your claim that `there are things that can only be learned by asking specific questions in NG's like this one': if you type `lisp closure' at google the *first* hit you get is David Lamkins' excellent `successful lisp' book. Was it too hard to do that?
Mark Conrad wrote: > I am trying to learn how to use Paul Graham's macros to implement > continuations in CL.
> In order to do that, I have to learn enough about scope and extent > issues peculiar to his macros.
> The text and examples in his book do not go into sufficient detail > about toplevel bindings and extent issues of his global variable > "*cont*" in his book.
> Specifically, my present 'learning-project' is to try to implement > catch/throw using continuations only, i.e. to pretend that catch and > throw do not exist in CL.
Mark, you seem to be going down a path that has led others to destruction --- one, at least, in spectacular fashion.
The pattern is this.
Someone comes to Common Lisp. "Good language," he says, "but I don't like `X'. Why isn't `X' the way it is in C#, or Scheme, or Intercal?"
"Because of ZZ," replies the Lisp community represented on comp.lang.lisp.
"But I don't agree with ZZ."
"Well, maybe you will once you've learned a little more about how Lisp works."
"Not a chance. Tell you what. Lisp is supposed to be mutable, right? Well, I'll make it the way I want! That's it! I'll make it have brackets instead of parentheses, or continuations instead of catch and throw, or whatever. Oh, by the way, the Lisp standard is broken, backquote doesn't work the way the standard says. And closures aren't what you think they are, and...."
The next thing you know, there are black helicopters overhead and you are being detained for questioning by the masses.
I take it you do have your personal affairs in order?
(For the humor impaired, the above is ENTIRELY tongue-in-cheek!)
-- Fred Gilham gil...@csl.sri.com Multiculturalism: The view that societal comity is best achieved by dividing the country into groups that hate each other. -- Fred Reed