I <car...@cartan.de> wrote: > Aleksandr Skobelev <public-m...@list.ru> writes:
> > Here the lexical binding to 30 shadows the dynamic binding to 20, > > which is in dynamic, but not the global environment. But eval sees > > 20, not 10. So, isn't null lexical environment equivalent to a some > > dynamic + the global environment?
> No. EVAL can access /both/ a null lexical environment (meaning the > lexically apparent binding of x to 30 isn't visible) /and/ the current > dynamic environment.
Aargh, this sounds dumb. We say ``null lexical environment´´ only to emphasize that no lexically apparent binding is visible. That implies that evaluating a form in a null lexical environment is ``equivalent´´ to evaluating it in the global environment -- but the bindings of dynamic variables are /part/ of the global environment! So it isn't really necessary to say ``some dynamic + the global environment´´ because the latter contains the former, anyway. But understanding your example is made easier if one emphasizes that the current dynamic environment is indeed visible.
Sorry, -- Nils Gösche "Don't ask for whom the <CTRL-G> tolls."
> There is indeed no lexically apparent binding for those two > symbols. But their values are looked up somewhere, in an > environment. Which is it?
Let me be pedantic here. The examples you are giving are fragments of lisp code. Within these fragments are `identifiers' (symbolic tokens with names such as "let", "x", and "declare") and `literals' (things like 17). Some of the identifiers refer to `variables', some refer to special syntactic forms. An identifier may refer to a `bound' variable, or it may be a `free' variable. There are two rules for evaluating a bound variable: If the variable is not `special', use the binding in the closest lexical context. If the variable *is* `special', look in the `value cell' of the symbol with the same name as the variable.
There is a special evaluation rule for free variables: always look in the `value cell' of the symbol with the same name as the variable.
> Neither MOST-POSITIVE-DOUBLE-FLOAT nor X have been declaimed > special, however.
the variables `most-positive-double-float' and `x' are free variables, so the rule for free variables applies and the value cell is used. (The rule for lexical variables does *not* apply because there is no lexical binding.)
> The global environment, obviously, which is also called ``null > lexical environment´´ to emphasize that it contains no lexically > apparent bindings (see 3.1.1.3.1 The Null Lexical Environment).
> Now, MOST-POSITIVE-DOUBLE-FLOAT is a constant, which is not so > interesting, but X is not. I can do
> CL-USER 33 > (setf (symbol-value 'x) 17) > 17
> CL-USER 34 > (eval 'x) > 17
> anytime I want. I can also do
This uses the free variable rule.
> CL-USER 35 > (let ((x 13)) > (+ x 5)) > 18
This uses the lexical variable rule.
> I would also like to try the following:
> (defun test (y) > (+ x y))
Note that in the function TEST, the variable `x' is free, so the free variable rule is used: the value cell of the symbol X will be used.
> (let ((x 20)) > (test 7))
But in this fragment, `x' is lexically bound. There is no way that the function TEST (or any other function) can refer to this binding.
> Now, 3.2.2.3 Semantic Constraints says:
> # Special proclamations for dynamic variables must be made in the > # compilation environment. Any binding for which there is no > # special declaration or proclamation in the compilation > # environment is treated by the compiler as a lexical binding.
In other words, if `x' is not special, then (let ((x 22)) ...) establishes a lexical binding for `x', not a special binding.
> But I might snottily claim that I don't want X to be special, > anyway :-)
> But what the heck, let's do it anyway:
> CL-USER 36 > (defun test (y) > (+ x y)) > Warning: Syntactic warning for form X: > X assumed special. > TEST
> CL-USER 37 > (let ((x 20)) > (test 7)) > 24
> as expected.
> Whether this is legal code or not is not so interesting at the > moment; what I like is that we can explain everything that > happened in the above experiments without resorting to > implementation issues if we simply say that X is part of such a > thing as a ``global lexical environment´´.
Well, I suppose you can call the collection of all value cells the `global lexical environment', but I wouldn't.
> While this sounds a bit like an oxymoron because lexical bindings > are usually lexically restricted to establishing forms and have > dynamic extent, it is well possible to give the term a reasonable > meaning.
Lexical variables have indefinite extent (you might close over them).
> Now, what happens if we do
> CL-USER 38 > (declaim (special x)) > NIL
> CL-USER 39 > (let ((x 20)) > (test 7)) > 27
> By globally declaring X special, we instruct the system to > perform the last binding in the dynamic environment, instead. It > is rather puzzling that TEST already behaves accordingly, too!
It shouldn't be puzzling. When you declaim X to be special, you explicitly tell the compiler that when X is bound (as in the LET statement that follows) the value cell of the symbol X should hold the binding.
> So, now X is also part of the (global) dynamic environment, > obviously. And it has kept its value :-)
I wouldn't say it quite that way. By declaiming X to be special, you have changed the binding discipline for that variable. It keeps its value in either case, it is just a matter of where that value is stored (and of course the dynamic extent of the binding).
* Rob Warnock | Well, it *can*, of course, access any new lexical bindings introduced in | the expression being EVAL'd, as well as any lexical bindings previously | closed over by functions called by the EVAL'd code. You didn't really | mean to exclude those when you said "/no/ lexical ones", did you?
I fail to grasp what the problem is. The function `eval´ is no different from any other function. That is the key. No other function can access the caller's lexical environment, either. WTF is so special about `eval´ that it needs all this bogus attention? Yes, you call a function that has captured some lexical bindings, but that does not change the fact that function /calls/ in Common Lisp do not, cannot, know anything about the caller's lexical environment.
-- Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.
> > There is indeed no lexically apparent binding for those two > > symbols. But their values are looked up somewhere, in an > > environment. Which is it?
[snip]
> There is a special evaluation rule for free variables: always look > in the `value cell' of the symbol with the same name as the > variable.
Yes, that this is what's actually done has been clear all the time. I had been trying to explain all those evaluations /without/ referring to this technique, I called that ``referring to the implementation´´, rather than pure semantics. But maybe that was my mistake: This lookup technique is actually part of the abstract semantics of the language (at least if all the snippets are legal). The ease with which you can explain everything now is certainly compelling, especially when compared to my clumsy attempts of doing everything with types of environments that don't even exist in the first place :-)
> > While this sounds a bit like an oxymoron because lexical bindings > > are usually lexically restricted to establishing forms and have > > dynamic extent, it is well possible to give the term a reasonable > > meaning.
> Lexical variables have indefinite extent (you might close over > them).
Yes, sorry again about this typo/thinko.
> > So, now X is also part of the (global) dynamic environment, > > obviously. And it has kept its value :-)
> I wouldn't say it quite that way. By declaiming X to be special, > you have changed the binding discipline for that variable. It keeps > its value in either case, it is just a matter of where that value is > stored (and of course the dynamic extent of the binding).
Sounds much better, indeed. Thanks for your patience.
Regards, -- Nils Gösche "Don't ask for whom the <CTRL-G> tolls."
> Nice example, actually. Although you should somehow globally declare > X special, maybe by using DEFPARAMETER instead of just SETF, to clear > all doubt.
Thanks. :) But it'd be an error to claim X special globally, because it'd make all bindings for X dynamic. Whereas we need both dynamic and lexical bindings here. (This example was produced under CMUCL with '(setf *top-level-auto-declare* nil)' that switched off autodeclaration of free global variables to be special.)
Nils Goesche <car...@cartan.de> writes: > I <car...@cartan.de> wrote:
> > No. EVAL can access /both/ a null lexical environment (meaning the > > lexically apparent binding of x to 30 isn't visible) /and/ the current > > dynamic environment.
> Aargh, this sounds dumb. We say ``null lexical environment´´ only to > emphasize that no lexically apparent binding is visible. That implies > that evaluating a form in a null lexical environment is ``equivalent´´ > to evaluating it in the global environment -- but the bindings of > dynamic variables are /part/ of the global environment!
I'm not sure. For the global environment contains bindings with indefinite scope and indefinite extent, while dynamic binding in LET form has dynamic extent (limited inside the form).
> So it isn't > really necessary to say ``some dynamic + the global environment´´ > because the latter contains the former, anyway.
I inclined to consider them as different notions. The global environment is an object of environment class that "contains, among other things, the following:
* bindings of dynamic variables and constant variables. * bindings of functions, macros, and special operators. * bindings of compiler macros. * bindings of type and class names * information about proclamations."
There is only one such object.
A dynamic environment is a class of environment that "contains, among other things, the following:
* bindings for dynamic variables. * information about active catch tags. * information about exit points established by unwind-protect. * information about active handlers and restarts."
So I see that each class contains information that is not in other. And because of that I don't able to say that one class include other.
If consider model where several Lisp processes run there are only one global environment and several dynamic environments simultaneously (one per process).
That are my reasonings. But they of course might have some, still undisclosed for me, deficiencies.
> > Nice example, actually. Although you should somehow globally > > declare X special, maybe by using DEFPARAMETER instead of just > > SETF, to clear all doubt.
> Thanks. :) But it'd be an error to claim X special globally, because > it'd make all bindings for X dynamic. Whereas we need both dynamic > and lexical bindings here.
Duh! Correct, sorry. I guess I am too tired today. I'll go home and have some sleep now.
Regards, -- Nils Gösche "Don't ask for whom the <CTRL-G> tolls."
Aleksandr Skobelev <public-m...@list.ru> writes: > Nils Goesche <car...@cartan.de> writes: > > We say ``null lexical environment´´ only to emphasize that no > > lexically apparent binding is visible. That implies that > > evaluating a form in a null lexical environment is ``equivalent´´ > > to evaluating it in the global environment -- but the bindings of > > dynamic variables are /part/ of the global environment!
> I'm not sure. For the global environment contains bindings with > indefinite scope and indefinite extent, while dynamic binding in LET > form has dynamic extent (limited inside the form).
I don't think it makes much of a difference whether you define it one way or the other. For instance, we have
# 3.1.2.1.1.2 Dynamic Variables
# At any given time, all dynamic variables with a given name refer to # exactly one binding, either in the dynamic environment or in the # global environment.
> > So it isn't really necessary to say ``some dynamic + the global > > environment´´ because the latter contains the former, anyway.
Ok, this seems to be imprecise (or even wrong).
> I inclined to consider them as different notions. The global > environment is an object of environment class that "contains, among > other things, the following:
[snip]
> So I see that each class contains information that is not in > other. And because of that I don't able to say that one class > include other.
Ok.
> That are my reasonings. But they of course might have some, still > undisclosed for me, deficiencies.
Sounds good to me.
Regards, -- Nils Gösche "Don't ask for whom the <CTRL-G> tolls."
Erik Naggum <e...@naggum.no> writes: > The function `eval´ is no different from any other function. That > is the key. No other function can access the caller's lexical > environment, either. WTF is so special about `eval´ that it needs > all this bogus attention? Yes, you call a function that has > captured some lexical bindings, but that does not change the fact > that function /calls/ in Common Lisp do not, cannot, know anything > about the caller's lexical environment.
So the necessary parts of the calling function's environment must be explicitly passed to the callee. Hm. Not your father's dynamic Lisp.
Do people who are up to speed in CL use flet and labels when they can, or do they tend to define everything at top level?
Is there an advantage to using flet instead of labels when the code doesn't require using labels?
> Do people who are up to speed in CL use flet and labels when they can, > or do they tend to define everything at top level?
I use both quite a lot. I often write (large) functions which are actually a bundle of local functions which do the work. They may (but may not) use lexical bindings from the parent, but in any case all those functions are only needed in one place, why define them globally?
But my style is probably quite idiosyncratic - the resulting 50-300 line functions might make people queasy until they realise that they are actually complete little worlds, like cheap packages...
> Is there an advantage to using flet instead of labels when the code > doesn't require using labels?
Sometimes (not often) it requires FLET, for instance shadowing a global (non-CL-defined) function (there are good uses for this, honest!)
--tim (this article makes me sound like the worst kind of hacker...)
Nils Goesche <car...@cartan.de> writes: > > > So it isn't really necessary to say ``some dynamic + the global > > > environment´´ because the latter contains the former, anyway.
> Ok, this seems to be imprecise (or even wrong).
In threaded code, I take it that each thread has its own dynamic environment, but shares the global environment.
Erik Naggum <e...@naggum.no> writes: > WTF is so special about `eval´ that it needs all this bogus > attention? Yes, you call a function that has captured some > lexical bindings, but that does not change the fact that function > /calls/ in Common Lisp do not, cannot, know anything about the > caller's lexical environment.
Actually, it is surprising to me (not being that familiar with CL) that eval did not do its thing in the environment of the let. I looked it up, and now understand that it uses the global environment. Why would it be designed that way?
> > WTF is so special about `eval´ that it needs all this bogus > > attention? Yes, you call a function that has captured some > > lexical bindings, but that does not change the fact that function > > /calls/ in Common Lisp do not, cannot, know anything about the > > caller's lexical environment.
> Actually, it is surprising to me (not being that familiar with CL) > that eval did not do its thing in the environment of the let. I > looked it up, and now understand that it uses the global environment. > Why would it be designed that way?
Rather, ask why it wouldn't. EVAL is just a function like any other. It takes its argument, which it then interprets as CL code[*]. A complete CL interpreter in CL only takes a few hundred lines of code, after all, so there's no need for any magic.
If you could capture the current runtime lexical environment as an object, then you could write a two-argument EVAL. But that would have horrible performance implications, for very little real benefit.
[*] It can "interpret" it by compiling, of course.
-- /|_ .-----------------------. ,' .\ / | No to Imperialist war | ,--' _,' | Wage class war! | / / `-----------------------' ( -. | | ) | (`-. '--.) `. )----'
Kurt B. Kaiser wrote: > Actually, it is surprising to me (not being that familiar with CL) > that eval did not do its thing in the environment of the let. I > looked it up, and now understand that it uses the global environment. > Why would it be designed that way?
From the spec (3.8.4 eval):
"Examples:
(setq form '(1+ a) a 999) 999 (eval form) 1000 (eval 'form) (1+ A) (let ((a '(this would break if eval used local value))) (eval form)) 1000"
ie, dont think of eval as only being used for a literal form (if I am guessing correctly the source of your surprise).
--
kenny tilton clinisys, inc --------------------------------------------------------------- ""Well, I've wrestled with reality for thirty-five years, Doctor, and I'm happy to state I finally won out over it."" Elwood P. Dowd
Kenny Tilton <ktil...@nyc.rr.com> writes: > Kurt B. Kaiser wrote: > > Actually, it is surprising to me (not being that familiar with CL) > > that eval did not do its thing in the environment of the let. I > > looked it up, and now understand that it uses the global environment. > > Why would it be designed that way?
> From the spec (3.8.4 eval):
> "Examples:
> (setq form '(1+ a) a 999) 999 > (eval form) 1000 > (eval 'form) (1+ A) > (let ((a '(this would break if eval used local value))) (eval form)) > 1000"
> ie, dont think of eval as only being used for a literal form (if I am > guessing correctly the source of your surprise).
Hyperspec:
"Evaluates form in the current dynamic environment and the null [i.e. empty] lexical environment."
ANSI CL (Graham): "(eval expression) Evaluates expression in the global environment."
I was using the latter until I read your post. To me, there is a difference, e.g. threads.
Hm. Using the dynamic environment makes more sense to me.
No, what surprised me was that the "lexical" x in the let didn't shadow the prior dynamic x.
* Kurt B. Kaiser | Actually, it is surprising to me (not being that familiar with CL) that | eval did not do its thing in the environment of the let. I looked it up, | and now understand that it uses the global environment. Why would it be | designed that way?
Because it is an ordinary function.
I am genuinely puzzled: Why is this so hard to grasp?
-- Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.
Erik Naggum <e...@naggum.no> writes: > * Kurt B. Kaiser > | Actually, it is surprising to me (not being that familiar with CL) that > | eval did not do its thing in the environment of the let. I looked it up, > | and now understand that it uses the global environment. Why would it be > | designed that way?
> Because it is an ordinary function.
> I am genuinely puzzled: Why is this so hard to grasp?
HyperSpec: "Note that an eval form involves two levels of evaluation for its argument. First, form is evaluated by the normal argument evaluation mechanism as would occur with any call. The object that results from this normal argument evaluation becomes the value of the form parameter, and is then evaluated as part of the eval form. "
In light of this (especially the second sentence), and using Skobelev's example from the other side of this thread,
---------- * (setf x 10) Warning: This variable is undefined: X
I would have expected eval to evaluate its argument in the lexical environment of the let block. Other functions, like print, have their arguments evaluated in that lexical environment before being passed.
However, the _effect_ of eval seems to be not quite like other functions because when it evaluates its argument it does so in the current dynamic environment, and that is definitely not what I was expecting. Maybe if it was called dynamic-eval I would have caught on immediately.
* Eric Naggum
> "Now, if you make no lexical bindings on this fresh set of overlays, > you have the null lexical environment. This is what `eval starts > out with, just like any other function before it makes its own > lexical bindings, such as for incoming arguments (which may also > cause special bindings, btw)."
You can think of it that way but isn't "null lexical environment" just a fancy way of saying (and emphasizing) "no lexical environment?" So, attempting to extend your example for the case of eval, can one say the dynamic overlay is flipped into place and the lexical overlay is not? Can eval write on the "lexical overlay"?
On a slightly different, but closely related, subject, I find it confusing that the `special declaration also "punches holes" in those parts of the lexical overlay which were created after the last dynamic binding, as in the example. In this case, my intuition expected the x in the let to shadow the dynamic binding, but clearly I'm getting an intuition upgrade.
* Kurt B. Kaiser | I would have expected eval to evaluate its argument in the lexical | environment of the let block.
But /why/? When you quote x, you explicitly request that it /not/ be evaluated. You pass `eval´ a symbol, not a value from the lexical environment. If you want the latter effect, do not quote x.
| Other functions, like print, have their arguments evaluated in that | lexical environment before being passed.
If you try `(print 'x)´, it will print `x´, not the value thereof.
| However, the _effect_ of eval seems to be not quite like other functions | because when it evaluates its argument it does so in the current dynamic | environment, and that is definitely not what I was expecting.
All other functions do the same. This is how function evaluation works. This is how the dynamic environment works.
| On a slightly different, but closely related, subject, I find it | confusing that the `special declaration also "punches holes" in those | parts of the lexical overlay which were created after the last dynamic | binding, as in the example.
I have no idea what this means.
I believe you still think in a different language and are unwilling to let go of what you believe you understand. Like perhaps `eval´ in Perl.
-- Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.
Kurt B. Kaiser wrote: > However, the _effect_ of eval seems to be not quite like other > functions because when it evaluates its argument it does so in the > current dynamic environment, and that is definitely not what I was > expecting.
I am no expert on eval or anything else for that matter, but when I look at the above, I would be appalled if the evaluation of some-code were affected by the lexical bindings of a, b, and c.
But dynamic bindings (to my way of thinking) are inescapable, hence some-code "seeing" those.
Like everything else about Lisp, it works exactly as I need, want, and would expect it to work since the value held by the parameter some-code was born lexically elsewhere and seen originally by the compiler as literal, symbolic data only /later/ to be promoted to runnable code by eval.
--
kenny tilton clinisys, inc --------------------------------------------------------------- ""Well, I've wrestled with reality for thirty-five years, Doctor, and I'm happy to state I finally won out over it."" Elwood P. Dowd
* Kenny Tilton | (defun interpret-this (some-code) | (let ((a 1) (b 2) (c :whatever)) | (eval some-code))) | | I am no expert on eval or anything else for that matter, but when I look | at the above, I would be appalled if the evaluation of some-code were | affected by the lexical bindings of a, b, and c.
Do not forget `some-code´ in this list.
Your example is instructive for quite another reason. Do those who think that `eval´ should "work" in the lexical environment of the caller, also think this should hold for calls to `interpret-this´? If not, why not?
-- Erik Naggum, Oslo, Norway
Act from reason, and failure makes you rethink and study harder. Act from faith, and failure makes you blame someone and push harder.
Erik Naggum <e...@naggum.no> writes: > I am genuinely puzzled: Why is this so hard to grasp?
I certainly was surprised the first time I used `eval' in Common Lisp. I was used to `eval'-ing things in Emacs Lisp, and Emacs Lisp doesn't have lexical bindings. I didn't consider the implications on lexical bindings on `eval'.
-- (domestic pets only, the antidote for overdose, milk.) la...@gnus.org * Lars Magne Ingebrigtsen
> I would have expected eval to evaluate its argument in the lexical > environment of the let block. Other functions, like print, have their > arguments evaluated in that lexical environment before being passed.