* Elisp lexical-let @ 2009-07-21 19:48 Daniel Kraft 2009-07-21 21:46 ` Ken Raeburn 2009-07-23 22:39 ` Andy Wingo 0 siblings, 2 replies; 18+ messages in thread From: Daniel Kraft @ 2009-07-21 19:48 UTC (permalink / raw) To: Ken Raeburn; +Cc: guile-devel Hi again, I just had some doubts about the details of lexical-let for elisp, which seem to be not answered by the document I linked to... Maybe you can clarify these to me. Especially, the question is about "what happens" when a lexical variable is inside its scope again bound dynamically (say via let or a lambda expression). Like in this example (I'm not sure if all my expected outputs are right, please correct me as needed): (defvar x 1) (defun foo () x) (lexical-let ((x 2)) x ; -> 2 (foo) ; -> 1 (setq x 3) x ; -> 3 (foo) ; -> 1 (let ((x 4)) x ; -> 4? (foo) ; -> 4 (setq x 5) x ; -> 5 (foo) ; -> 5 ) ; end the let x ; -> 3? (foo) ; -> 4 ) x ; -> 4 (foo) ; -> 4 So in this case all references to x in the lexical scope of the let are to the dynamic value again, while the lexical is untouched and restored after leaving the let? Have a nice evening! Daniel -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-21 19:48 Elisp lexical-let Daniel Kraft @ 2009-07-21 21:46 ` Ken Raeburn 2009-07-22 9:11 ` Daniel Kraft 2009-07-23 22:39 ` Andy Wingo 1 sibling, 1 reply; 18+ messages in thread From: Ken Raeburn @ 2009-07-21 21:46 UTC (permalink / raw) To: Daniel Kraft; +Cc: guile-devel On Jul 21, 2009, at 15:48, Daniel Kraft wrote: > Especially, the question is about "what happens" when a lexical > variable is inside its scope again bound dynamically (say via let or > a lambda expression). Oh, don't stop there... let's get some buffer-local or frame-local bindings into the mix too! :-) There are probably corner cases where the only "specification" you're likely to find is "what Emacs does when you try it". And, if the goal is to support the existing body of Lisp code (e.g., if Emacs 24 goes out with lexical binding support, and people start using it), there's a tradeoff between what seems logical or convenient to you, and what behavior of Emacs the existing code is going to expect. Maybe not in weird corner cases, but cases like you describe above seem likely, and I think you'd want to mimic whatever behavior Emacs is going to do. Ken ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-21 21:46 ` Ken Raeburn @ 2009-07-22 9:11 ` Daniel Kraft 2009-07-22 13:00 ` Marijn Schouten (hkBst) ` (2 more replies) 0 siblings, 3 replies; 18+ messages in thread From: Daniel Kraft @ 2009-07-22 9:11 UTC (permalink / raw) To: Ken Raeburn, Andy Wingo, Neil Jerram; +Cc: guile-devel Ken Raeburn wrote: > On Jul 21, 2009, at 15:48, Daniel Kraft wrote: >> Especially, the question is about "what happens" when a lexical >> variable is inside its scope again bound dynamically (say via let or a >> lambda expression). > > Oh, don't stop there... let's get some buffer-local or frame-local > bindings into the mix too! :-) > There are probably corner cases where the only "specification" you're > likely to find is "what Emacs does when you try it". And, if the goal > is to support the existing body of Lisp code (e.g., if Emacs 24 goes out > with lexical binding support, and people start using it), there's a > tradeoff between what seems logical or convenient to you, and what > behavior of Emacs the existing code is going to expect. Maybe not in > weird corner cases, but cases like you describe above seem likely, and I > think you'd want to mimic whatever behavior Emacs is going to do. It seemed really hard to me to find at least *basic* information about how the lexbind things works; I did build now an emacs with lexbind from trunk, but so far as I see this is not meant to implement "lexical-let" as the cl package does, but rather allows switching all bindings from dynamic to lexical within one source file. While this is certainly something we could do, too (best via compiler options, I guess?), it is not what I had in mind as the "extension" -- this being implementing the lexical-let as additional construct that establishes lexical binding for certain variables just temporarily. And checks with the cl package's implementation of lexical-let give the result, that an inner let does the same as if it was another lexical-let; that is, does not revert to dynamic binding but rather sets only the lexical value. So, what are the opinions regarding lexical-let as an extension construct? Regarding the behaviour, to me the one described above seems to be a consequence of the implementing with unwind-protect and not necessarily expected -- thus I suggest to implement the version I had in mind, namely that an inner let or argument binding inside a lambda reverts to dynamic binding for that inner scope. This seems more consistent and reasonable to me. Yours, Daniel -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-22 9:11 ` Daniel Kraft @ 2009-07-22 13:00 ` Marijn Schouten (hkBst) 2009-07-22 19:24 ` Daniel Kraft 2009-07-22 20:50 ` Ken Raeburn 2009-07-23 20:49 ` Andy Wingo 2 siblings, 1 reply; 18+ messages in thread From: Marijn Schouten (hkBst) @ 2009-07-22 13:00 UTC (permalink / raw) To: Daniel Kraft; +Cc: Andy Wingo, Ken Raeburn, guile-devel, Neil Jerram -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Daniel Kraft wrote: > Ken Raeburn wrote: >> On Jul 21, 2009, at 15:48, Daniel Kraft wrote: >>> Especially, the question is about "what happens" when a lexical >>> variable is inside its scope again bound dynamically (say via let or >>> a lambda expression). >> >> Oh, don't stop there... let's get some buffer-local or frame-local >> bindings into the mix too! :-) >> There are probably corner cases where the only "specification" you're >> likely to find is "what Emacs does when you try it". And, if the goal >> is to support the existing body of Lisp code (e.g., if Emacs 24 goes >> out with lexical binding support, and people start using it), there's >> a tradeoff between what seems logical or convenient to you, and what >> behavior of Emacs the existing code is going to expect. Maybe not in >> weird corner cases, but cases like you describe above seem likely, and >> I think you'd want to mimic whatever behavior Emacs is going to do. > > It seemed really hard to me to find at least *basic* information about > how the lexbind things works; I did build now an emacs with lexbind from > trunk, but so far as I see this is not meant to implement "lexical-let" > as the cl package does, but rather allows switching all bindings from > dynamic to lexical within one source file. > > While this is certainly something we could do, too (best via compiler > options, I guess?), it is not what I had in mind as the "extension" -- > this being implementing the lexical-let as additional construct that > establishes lexical binding for certain variables just temporarily. > > And checks with the cl package's implementation of lexical-let give the > result, that an inner let does the same as if it was another > lexical-let; that is, does not revert to dynamic binding but rather sets > only the lexical value. > > So, what are the opinions regarding lexical-let as an extension > construct? Regarding the behaviour, to me the one described above seems > to be a consequence of the implementing with unwind-protect and not > necessarily expected -- thus I suggest to implement the version I had in > mind, namely that an inner let or argument binding inside a lambda > reverts to dynamic binding for that inner scope. This seems more > consistent and reasonable to me. > > Yours, > Daniel > Guile also has lexical and dynamic variables; the fluids[1]. Queinnec in his book LiSP also describes a system that has (default) lexical and dynamic variable, on page 44. In both cases to find the value of a non-default variable a function is used. Translated to elisp where the situation is dynamic by default you probably want something like `(lexical x)' to dereference the lexical variable `x' and also lexical-set(q). It seems to me that only the dereferencing of variables is dynamic or lexical, not the binding. Thus you don't even need lexical-let and `(lexical x)' would be `x' found in the lexical environment (if it isn't found you can generate an error) and `x' would be searched for in the dynamic environment. Does that make sense? [1]:http://www.gnu.org/software/guile/manual/guile.html#Fluids-and-Dynamic-States Marijn - -- If you cannot read my mind, then listen to what I say. Marijn Schouten (hkBst), Gentoo Lisp project, Gentoo ML <http://www.gentoo.org/proj/en/lisp/>, #gentoo-{lisp,ml} on FreeNode -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.11 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkpnDXgACgkQp/VmCx0OL2zpcgCgg2QtK7kL5YJCeVP6hpG87h0f DCMAn3rgkDIk2GYBqnHJ/JRzjsW7ehBw =e0Hz -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-22 13:00 ` Marijn Schouten (hkBst) @ 2009-07-22 19:24 ` Daniel Kraft 2009-07-23 15:24 ` Marijn Schouten (hkBst) 0 siblings, 1 reply; 18+ messages in thread From: Daniel Kraft @ 2009-07-22 19:24 UTC (permalink / raw) To: Marijn Schouten (hkBst); +Cc: Andy Wingo, Ken Raeburn, guile-devel, Neil Jerram Hi Marijn, Marijn Schouten (hkBst) wrote: > Guile also has lexical and dynamic variables; the fluids[1]. Queinnec in his > book LiSP also describes a system that has (default) lexical and dynamic > variable, on page 44. In both cases to find the value of a non-default variable > a function is used. Translated to elisp where the situation is dynamic by > default you probably want something like `(lexical x)' to dereference the > lexical variable `x' and also lexical-set(q). > > It seems to me that only the dereferencing of variables is dynamic or lexical, > not the binding. Thus you don't even need lexical-let and `(lexical x)' would be > `x' found in the lexical environment (if it isn't found you can generate an > error) and `x' would be searched for in the dynamic environment. Does that make > sense? not only the dereferencing, but also the setting must be of a dynamic or lexical value; and at least in my Lisp code, setting is mostly done with let's, so at the same time as the "binding". So what you propose would then be to have a (lexical sym) for referencing and (lexical-set! sym value) for setting in lexical scope -- and then as a consequence also a lexical-let, that does let but sets to the provided values just as lexical-set! does...? Well, that's how I see it, anyways. And while your arguments seem quite reasonable (decide for each access of a symbol between lexical and dynamic), I think this creates a superfluous amount of confusion and "just" switching for certain variables to lexical binding within the scope of a lexical-let seems to me the better solution. What's about this: (defun test () a) (let ((a 1)) (print a) ; 1 (print (test)) ; 1 (lexical-set! a 2) (print a) ; 1? (print (test)) ; 1 (print (lexical a)) ; 2 ) I don't think it's good to have to "completely seperate" variables a and (lexical a). And besides, here there's no way to decide that no fluids at all are needed for a, as the let construct itself (except the references following) still creates a with-fluids* call. Yours, Daniel PS: From a performance point of view, I guess that the void checks on each variable access are far more expensive than the fluid/dynamic-scoping business. But I'll report on this (performance) maybe in a seperate posting when I've done some experiments and real data as well as suggestions. -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-22 19:24 ` Daniel Kraft @ 2009-07-23 15:24 ` Marijn Schouten (hkBst) 2009-07-23 16:13 ` Mark H Weaver 2009-07-23 17:05 ` Daniel Kraft 0 siblings, 2 replies; 18+ messages in thread From: Marijn Schouten (hkBst) @ 2009-07-23 15:24 UTC (permalink / raw) To: Daniel Kraft; +Cc: Andy Wingo, Ken Raeburn, guile-devel, Neil Jerram -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Daniel Kraft wrote: > Hi Marijn, > > Marijn Schouten (hkBst) wrote: >> Guile also has lexical and dynamic variables; the fluids[1]. Queinnec >> in his >> book LiSP also describes a system that has (default) lexical and dynamic >> variable, on page 44. In both cases to find the value of a non-default >> variable >> a function is used. Translated to elisp where the situation is dynamic by >> default you probably want something like `(lexical x)' to dereference the >> lexical variable `x' and also lexical-set(q). >> >> It seems to me that only the dereferencing of variables is dynamic or >> lexical, >> not the binding. Thus you don't even need lexical-let and `(lexical >> x)' would be >> `x' found in the lexical environment (if it isn't found you can >> generate an >> error) and `x' would be searched for in the dynamic environment. Does >> that make >> sense? > > not only the dereferencing, but also the setting must be of a dynamic or > lexical value; yes and one could argue that to set a variable you need to dereference it first too or you won't know which location you're set'ting. > and at least in my Lisp code, setting is mostly done with > let's, so at the same time as the "binding". Unless elisp is the exception, let does not set any variables, but only introduces bindings. > So what you propose would then be to have a (lexical sym) for > referencing and (lexical-set! sym value) for setting in lexical scope -- yes. > and then as a consequence also a lexical-let, that does let but sets to > the provided values just as lexical-set! does...? Well, that's how I > see it, anyways. no, let does no assignement AFAIK. > And while your arguments seem quite reasonable (decide for each access > of a symbol between lexical and dynamic), I think this creates a > superfluous amount of confusion and "just" switching for certain > variables to lexical binding within the scope of a lexical-let seems to > me the better solution. Aha, now I understand what you want lexical-let to mean. If you are explicit about each variable access how can that be confusing? Possibly confusing is if you have to examine the complete enclosing context for lexical-let's. > What's about this: > > (defun test () a) > (let ((a 1)) > (print a) ; 1 > (print (test)) ; 1 > (lexical-set! a 2) there is only one variable `a' in my mental model, so this changes the value of the only `a' and all subsequent expressions accessing `a' are thus affected. The same as if you had written `(set! a 2)'. Dynamic and lexical only differ in how free variables in procedures are bound. > (print a) ; 1? no, (print a) => 2 > (print (test)) ; 1 no, there is only one `a' and its value is 2 here > (print (lexical a)) ; 2 > ) > > I don't think it's good to have to "completely seperate" variables a and > (lexical a). I don't understand what you mean. My proposal is to have one kind of variable and two kinds of access. > And besides, here there's no way to decide that no fluids > at all are needed for a, as the let construct itself (except the > references following) still creates a with-fluids* call. For the calls above all the dynamic accesses can be determined statically. Lexical accesses can always be determined statically. Thus all accesses in this example can be determined statically and can be compiled to a location dereference (either read or write). Nothing in the semantics is inherently inefficient. Marijn - -- If you cannot read my mind, then listen to what I say. Marijn Schouten (hkBst), Gentoo Lisp project, Gentoo ML <http://www.gentoo.org/proj/en/lisp/>, #gentoo-{lisp,ml} on FreeNode -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.11 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkpogK0ACgkQp/VmCx0OL2x4JACgwYR+48aAHTjMu1S6H7Dw4utR YzoAn3hMwhEadhlrAw7a06gWZBEoDWQX =DkN6 -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-23 15:24 ` Marijn Schouten (hkBst) @ 2009-07-23 16:13 ` Mark H Weaver 2009-07-23 20:53 ` Andy Wingo 2009-07-23 17:05 ` Daniel Kraft 1 sibling, 1 reply; 18+ messages in thread From: Mark H Weaver @ 2009-07-23 16:13 UTC (permalink / raw) To: Marijn Schouten (hkBst) Cc: Andy Wingo, Neil Jerram, Daniel Kraft, Ken Raeburn, guile-devel On Thu, Jul 23, 2009 at 05:24:30PM +0200, Marijn Schouten (hkBst) wrote: > For the calls above all the dynamic accesses can be determined statically. > Lexical accesses can always be determined statically. Thus all accesses in this > example can be determined statically and can be compiled to a location > dereference (either read or write). Nothing in the semantics is inherently > inefficient. There is at least one inherent loss of efficiency with the semantics you propose: with a lexical-let binding, the compiler can determine statically whether the variable is non-mutable, because the only place it could possibly be set! is within the lexical scope. Non-mutable variables can safely be inlined, an especially important optimization, especially if the value is a procedure. Also, with lexical-let, the compiler knows statically the entire set of references, which can be helpful with many analyses, for example whether continuations or closures can "escape" a particular scope, whether a particular continuation might be invoked more than once, etc. Regards, Mark ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-23 16:13 ` Mark H Weaver @ 2009-07-23 20:53 ` Andy Wingo 0 siblings, 0 replies; 18+ messages in thread From: Andy Wingo @ 2009-07-23 20:53 UTC (permalink / raw) To: Mark H Weaver; +Cc: guile-devel, Neil Jerram, Daniel Kraft, Ken Raeburn Hi, Just for the record :) On Thu 23 Jul 2009 18:13, Mark H Weaver <mhw@netris.org> writes: > On Thu, Jul 23, 2009 at 05:24:30PM +0200, Marijn Schouten (hkBst) wrote: >> For the calls above all the dynamic accesses can be determined statically. >> Lexical accesses can always be determined statically. Thus all accesses in this >> example can be determined statically and can be compiled to a location >> dereference (either read or write). Nothing in the semantics is inherently >> inefficient. > > There is at least one inherent loss of efficiency with the semantics > you propose: with a lexical-let binding, the compiler can determine > statically whether the variable is non-mutable, because the only place > it could possibly be set! is within the lexical scope. Non-mutable > variables can safely be inlined, an especially important optimization, > especially if the value is a procedure. Guile does detect this. The useful optimization is that variables that are never set! can be allocated on the stack, and if they're closed over, they can simply be copied. > Also, with lexical-let, the compiler knows statically the entire set > of references, which can be helpful with many analyses, for example > whether continuations or closures can "escape" a particular scope, > whether a particular continuation might be invoked more than once, > etc. This is a more tricky optimization :) Andy -- http://wingolog.org/ ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-23 15:24 ` Marijn Schouten (hkBst) 2009-07-23 16:13 ` Mark H Weaver @ 2009-07-23 17:05 ` Daniel Kraft 2009-07-24 11:09 ` Marijn Schouten (hkBst) 1 sibling, 1 reply; 18+ messages in thread From: Daniel Kraft @ 2009-07-23 17:05 UTC (permalink / raw) To: Marijn Schouten (hkBst); +Cc: Andy Wingo, Ken Raeburn, guile-devel, Neil Jerram Hi, thanks for your comments; I'm still a bit confused, though :$ Marijn Schouten (hkBst) wrote: >> What's about this: >> >> (defun test () a) >> (let ((a 1)) >> (print a) ; 1 >> (print (test)) ; 1 >> (lexical-set! a 2) > there is only one variable `a' in my mental model, > so this changes the value of the only `a' and all > subsequent expressions accessing `a' are thus affected. > The same as if you had written `(set! a 2)'. Dynamic > and lexical only differ in how free variables in > procedures are bound. >> (print a) ; 1? > no, (print a) => 2 >> (print (test)) ; 1 > no, there is only one `a' and its value is 2 here >> (print (lexical a)) ; 2 >> ) Hm... my problem is trying to understand how you want this implemented; my main point about lexical scoping is that it enables us to use Guile's built-in lexical mechanisms and we don't have to save the value explicitly into some fluids. But if you require that the second (print (test)) above prints 1 even though we have done (lexical-set! a) this means that lexical-set! must update the place somehow where a is accessed dynamically (as is done in test). And that seems to imply that this lexical-set! updates the fluids, even though it is meant to perform on a lexically bound variable a; just in case that "the one" a is at some place referred to dynamically. >> I don't think it's good to have to "completely seperate" variables a and >> (lexical a). > > I don't understand what you mean. My proposal is to have one kind of variable > and two kinds of access. Can you please elaborate on this? If there's only one variable and only the value 2 after the lexical-set! above (both for (print a) in the lexical scope and (print (test)) which accesses a dynamically), what would then be the point of writing 'a' or '(lexical a)' and what would be the difference between those two? Yours, Daniel -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-23 17:05 ` Daniel Kraft @ 2009-07-24 11:09 ` Marijn Schouten (hkBst) 0 siblings, 0 replies; 18+ messages in thread From: Marijn Schouten (hkBst) @ 2009-07-24 11:09 UTC (permalink / raw) To: Daniel Kraft; +Cc: Andy Wingo, Ken Raeburn, guile-devel, Neil Jerram -----BEGIN PGP SIGNED MESSAGE----- Hash: SHA1 Daniel Kraft wrote: > Hi, > > thanks for your comments; I'm still a bit confused, though :$ > > Marijn Schouten (hkBst) wrote: >>> What's about this: >>> >>> (defun test () a) >>> (let ((a 1)) >>> (print a) ; 1 >>> (print (test)) ; 1 >>> (lexical-set! a 2) >> there is only one variable `a' in my mental model, >> so this changes the value of the only `a' and all >> subsequent expressions accessing `a' are thus affected. >> The same as if you had written `(set! a 2)'. Dynamic >> and lexical only differ in how free variables in >> procedures are bound. >>> (print a) ; 1? >> no, (print a) => 2 >>> (print (test)) ; 1 >> no, there is only one `a' and its value is 2 here >>> (print (lexical a)) ; 2 >>> ) > > Hm... my problem is trying to understand how you want this implemented; > my main point about lexical scoping is that it enables us to use Guile's > built-in lexical mechanisms and we don't have to save the value > explicitly into some fluids. > > But if you require that the second (print (test)) above prints 1 even > though we have done (lexical-set! a) this means that lexical-set! must > update the place somehow where a is accessed dynamically (as is done in > test). And that seems to imply that this lexical-set! updates the > fluids, even though it is meant to perform on a lexically bound variable > a; just in case that "the one" a is at some place referred to dynamically. In my proposal it is meaningless to say "lexically bound variable", as all variables would in principal be accessible both lexically and dynamically. >>> I don't think it's good to have to "completely seperate" variables a and >>> (lexical a). >> >> I don't understand what you mean. My proposal is to have one kind of >> variable >> and two kinds of access. > > Can you please elaborate on this? If there's only one variable and only > the value 2 after the lexical-set! above (both for (print a) in the > lexical scope and (print (test)) which accesses a dynamically), what > would then be the point of writing 'a' or '(lexical a)' and what would > be the difference between those two? (defvar x 3) (defun dynx () x) (dynx) ; => 3 (defun lexx () (lexical x)) (lexx) ; => 3 (defun incdynx () (setq x (+ x 1))) (defun inclexx () (lexical-setq x (+ (lexical x) 1))) (let ((x 5)) (dynx) ; => 5 (lexx) ; => 3 (lexical-setq x 6) (dynx) ; => 6 (lexx) ; => 3 (setq x 7) (dynx) ; => 7 (lexx) ; => 3 (incdynx) (dynx) ; => 8 (lexx) ; => 3 (inclexx) (dynx) ; => 8 (lexx) ; => 4 ) (dynx) ; => 4 (lexx) ; => 4 (incdynx) (dynx) ; => 5 (lexx) ; => 5 (inclexx) (dynx) ; => 6 (lexx) ; => 6 I hope I haven't made any mistakes there and that it explains what I have in mind. Marijn - -- If you cannot read my mind, then listen to what I say. Marijn Schouten (hkBst), Gentoo Lisp project, Gentoo ML <http://www.gentoo.org/proj/en/lisp/>, #gentoo-{lisp,ml} on FreeNode -----BEGIN PGP SIGNATURE----- Version: GnuPG v2.0.11 (GNU/Linux) Comment: Using GnuPG with Mozilla - http://enigmail.mozdev.org iEYEARECAAYFAkpplk8ACgkQp/VmCx0OL2wFVACfV36PIQRwjQu3gGOc8Rly6h8Z UKQAnA5yPPMBNJsoRoc70+5znTP10r6G =SL2/ -----END PGP SIGNATURE----- ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-22 9:11 ` Daniel Kraft 2009-07-22 13:00 ` Marijn Schouten (hkBst) @ 2009-07-22 20:50 ` Ken Raeburn 2009-07-23 10:47 ` Daniel Kraft 2009-07-23 20:49 ` Andy Wingo 2 siblings, 1 reply; 18+ messages in thread From: Ken Raeburn @ 2009-07-22 20:50 UTC (permalink / raw) To: Daniel Kraft; +Cc: Andy Wingo, guile-devel, Neil Jerram On Jul 22, 2009, at 05:11, Daniel Kraft wrote: > It seemed really hard to me to find at least *basic* information > about how the lexbind things works; I did build now an emacs with > lexbind from trunk, but so far as I see this is not meant to > implement "lexical-let" as the cl package does, but rather allows > switching all bindings from dynamic to lexical within one source file. Oh... I may have seriously misunderstood; sorry about that. That's what comes from not having bothered to look. :-) In that case, the cl package is probably the thing to look at for now; it is used by a bunch of other things in Emacs. But I do expect lexbind is going to get merged in eventually, so keeping that in mind for the future would be wise too. > And checks with the cl package's implementation of lexical-let give > the result, that an inner let does the same as if it was another > lexical-let; that is, does not revert to dynamic binding but rather > sets only the lexical value. > > So, what are the opinions regarding lexical-let as an extension > construct? Regarding the behaviour, to me the one described above > seems to be a consequence of the implementing with unwind-protect > and not necessarily expected -- thus I suggest to implement the > version I had in mind, namely that an inner let or argument binding > inside a lambda reverts to dynamic binding for that inner scope. > This seems more consistent and reasonable to me. I think you could make an argument for doing it either way. The interesting question would be whether anyone is depending on the behavior from the cl package. Ken ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-22 20:50 ` Ken Raeburn @ 2009-07-23 10:47 ` Daniel Kraft 2009-07-23 20:56 ` Andy Wingo 0 siblings, 1 reply; 18+ messages in thread From: Daniel Kraft @ 2009-07-23 10:47 UTC (permalink / raw) To: Ken Raeburn; +Cc: Andy Wingo, guile-devel, Neil Jerram Ken Raeburn wrote: > On Jul 22, 2009, at 05:11, Daniel Kraft wrote: >> It seemed really hard to me to find at least *basic* information about >> how the lexbind things works; I did build now an emacs with lexbind >> from trunk, but so far as I see this is not meant to implement >> "lexical-let" as the cl package does, but rather allows switching all >> bindings from dynamic to lexical within one source file. > > Oh... I may have seriously misunderstood; sorry about that. That's what > comes from not having bothered to look. :-) Ok, I think I'll work on a cl like lexical-let now and see what this gives in performance related to dynamic let (and just to get it available of course). The implementation will (for now at least) be as I favour it, that is, inner lets revert to dynamic binding (as do inner lambdas for their arguments) -- this is more reasonable (I think), has more power (as the other way can be achieved by using lexical-let for inner lets when preferred, which is also clearer to understand) and should be easier to implement (because I don't need to mess around with the compilation of let constructs depending on the context). I'll keep in mind also the lexbind idea of optionally making every binding lexical. Andy, can you give me a hint/example/pointer how compiler options work? This would be exactly the place to provide this, I think. Additionally we could add an option to remove the "variable is void" error check for a further performance gain. Yours, Daniel -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-23 10:47 ` Daniel Kraft @ 2009-07-23 20:56 ` Andy Wingo 2009-07-24 6:50 ` Daniel Kraft 0 siblings, 1 reply; 18+ messages in thread From: Andy Wingo @ 2009-07-23 20:56 UTC (permalink / raw) To: Daniel Kraft; +Cc: Ken Raeburn, guile-devel, Neil Jerram Hi, On Thu 23 Jul 2009 12:47, Daniel Kraft <d@domob.eu> writes: > Ken Raeburn wrote: >> On Jul 22, 2009, at 05:11, Daniel Kraft wrote: >>> It seemed really hard to me to find at least *basic* information >>> about how the lexbind things works; I did build now an emacs with >>> lexbind from trunk, but so far as I see this is not meant to >>> implement "lexical-let" as the cl package does, but rather allows >>> switching all bindings from dynamic to lexical within one source >>> file. >> >> Oh... I may have seriously misunderstood; sorry about that. That's >> what comes from not having bothered to look. :-) > > Ok, I think I'll work on a cl like lexical-let now and see what this > gives in performance related to dynamic let (and just to get it > available of course). > > The implementation will (for now at least) be as I favour it, that is, > inner lets revert to dynamic binding (as do inner lambdas for their > arguments) -- this is more reasonable (I think), has more power (as the > other way can be achieved by using lexical-let for inner lets when > preferred, which is also clearer to understand) and should be easier to > implement (because I don't need to mess around with the compilation of > let constructs depending on the context). Fair enough. The other semantics sound pretty crazy. > I'll keep in mind also the lexbind idea of optionally making every > binding lexical. Andy, can you give me a hint/example/pointer how > compiler options work? This would be exactly the place to provide this, > I think. Additionally we could add an option to remove the "variable is > void" error check for a further performance gain. They don't work! Well, basically they're just a value that reaches the compiler somehow. I think they are a keyword list: (#:foo bar #:baz qux) etc. They are set via the #:opts argument to compile; I don't know if you can set them from the command line. I was waiting for a use case :) Peace, Andy -- http://wingolog.org/ ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-23 20:56 ` Andy Wingo @ 2009-07-24 6:50 ` Daniel Kraft 0 siblings, 0 replies; 18+ messages in thread From: Daniel Kraft @ 2009-07-24 6:50 UTC (permalink / raw) To: Andy Wingo; +Cc: Ken Raeburn, guile-devel, Neil Jerram Andy Wingo wrote: >> I'll keep in mind also the lexbind idea of optionally making every >> binding lexical. Andy, can you give me a hint/example/pointer how >> compiler options work? This would be exactly the place to provide this, >> I think. Additionally we could add an option to remove the "variable is >> void" error check for a further performance gain. > > They don't work! Well, basically they're just a value that reaches the > compiler somehow. I think they are a keyword list: (#:foo bar #:baz qux) > etc. They are set via the #:opts argument to compile; I don't know if > you can set them from the command line. I was waiting for a use case :) thanks for the hints, I did some tests yesterday, and it seems that I can just provide whatever value I want to (compile ... #:opts <options>) and get this as opts of the compiler routine called. I've never used keyword lists before, but I'll look them up and this seems like what we want. So far I'm thinking about two possibly useful options: 1) Declare to disable void checks for certain variables or all (for performance, as already written). Stuff like makunbound/boundp will sill work just as before, but accessing a variable that is void will not give an error but rather return the special void value. As most code should not really depend on this void-error anyways, it seems reasonable to give at least a way to disable this check happening on each and every variable access for no good (except debugging maybe). 2) Declare that certain variables or all should always be bound lexically rather than dynamically; maybe a defvar construct will retract this and make it dynamically bound later on again, then this should be like the upcoming lexbind stuff in emacs. As lexical-let is not everything, but function arguments are always dynamically bound (except if we provide a lexical-lambda... hm, it might even be useful at times!) -- and this spoils tail-calls -- both of this option and lexical-let will probably be useful. And maybe others in the future, but I've no ideas so far. It seems that options work basically, but I guess there's not yet a way to "set" them for compilation happening for the elisp-repl? This means that I can just keep on implementing and testing them, but for real use we probably want some construct to set them for real uses (besides (compile ...)) as well. Cheers, Daniel -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-22 9:11 ` Daniel Kraft 2009-07-22 13:00 ` Marijn Schouten (hkBst) 2009-07-22 20:50 ` Ken Raeburn @ 2009-07-23 20:49 ` Andy Wingo 2 siblings, 0 replies; 18+ messages in thread From: Andy Wingo @ 2009-07-23 20:49 UTC (permalink / raw) To: Daniel Kraft; +Cc: Ken Raeburn, guile-devel, Neil Jerram On Wed 22 Jul 2009 11:11, Daniel Kraft <d@domob.eu> writes: > And checks with the cl package's implementation of lexical-let give the > result, that an inner let does the same as if it was another > lexical-let; that is, does not revert to dynamic binding but rather sets > only the lexical value. Interesting -- so it has to codewalk the contained expressions, replacing let on its variables with appropriate lexical constructs? > So, what are the opinions regarding lexical-let as an extension > construct? Regarding the behaviour, to me the one described above seems > to be a consequence of the implementing with unwind-protect and not > necessarily expected -- thus I suggest to implement the version I had in > mind, namely that an inner let or argument binding inside a lambda > reverts to dynamic binding for that inner scope. This seems more > consistent and reasonable to me. I'm afraid we're going to have to do whatever the existing lexical-let does, if possible. Andy -- http://wingolog.org/ ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-21 19:48 Elisp lexical-let Daniel Kraft 2009-07-21 21:46 ` Ken Raeburn @ 2009-07-23 22:39 ` Andy Wingo 2009-07-24 7:08 ` Daniel Kraft 1 sibling, 1 reply; 18+ messages in thread From: Andy Wingo @ 2009-07-23 22:39 UTC (permalink / raw) To: Daniel Kraft; +Cc: Ken Raeburn, guile-devel On Tue 21 Jul 2009 21:48, Daniel Kraft <d@domob.eu> writes: > (defvar x 1) > (defun foo () x) > (lexical-let ((x 2)) > x ; -> 2 > (foo) ; -> 1 > (setq x 3) > x ; -> 3 > (foo) ; -> 1 > (let ((x 4)) > x ; -> 4? > (foo) ; -> 4 > (setq x 5) > x ; -> 5 > (foo) ; -> 5 > ) ; end the let > x ; -> 3? > (foo) ; -> 4 > ) > x ; -> 4 > (foo) ; -> 4 It's actually fairly simple, imo. Alpha-equivalence says that (lexical-let ((x a)) x) is the same as (lexical-let ((y a)) y). (Note that this lexical-let corresponds to Scheme's let.) So your program is the same as: > (lexical-let ((y 2)) > y ; -> 2 > (foo) ; -> 1 > (setq y 3) > y ; -> 3 > (foo) ; -> 1 > (let ((x 4)) > x ; -> 4? > (foo) ; -> 4 > (setq x 5) > x ; -> 5 > (foo) ; -> 5 > ) ; end the let > y ; -> 3? > (foo) ; -> 4 > ) > x ; -> 4 > (foo) ; -> 4 I haven't reviewed your compiler yet, and for that I apologize. But. You need to make sure that when you compile, you build up a compile-time environment, mapping symbols to locations -- if a variable is free, lexically bound, or dynamically bound. When your compiler sees a lexical binding, replace that identifier with a gensym, and add an entry to your compile-time environment to map that identifier to that lexical gensym. That way you will effectively be processing my example, which is equivalent to yours, but perhaps clearer because the names have been uniquified. Then your problems go away. Peace, Andy -- http://wingolog.org/ ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-23 22:39 ` Andy Wingo @ 2009-07-24 7:08 ` Daniel Kraft 2009-07-24 11:42 ` Andy Wingo 0 siblings, 1 reply; 18+ messages in thread From: Daniel Kraft @ 2009-07-24 7:08 UTC (permalink / raw) To: Andy Wingo; +Cc: Ken Raeburn, guile-devel Hi Andy, thanks for the clarifications! > It's actually fairly simple, imo. Alpha-equivalence says that > (lexical-let ((x a)) x) is the same as (lexical-let ((y a)) y). (Note > that this lexical-let corresponds to Scheme's let.) So your program is > the same as: > >> (lexical-let ((y 2)) >> y ; -> 2 >> (foo) ; -> 1 >> (setq y 3) >> y ; -> 3 >> (foo) ; -> 1 >> (let ((x 4)) >> x ; -> 4? >> (foo) ; -> 4 >> (setq x 5) >> x ; -> 5 >> (foo) ; -> 5 >> ) ; end the let >> y ; -> 3? >> (foo) ; -> 4 >> ) >> x ; -> 4 >> (foo) ; -> 4 Yes of course, my main question was how the inner let is handled, and what dynamic values x will attain (the results of (foo)) -- and here's this funny stuff that the inner let will be like lexical-let for those variables already lexically bound. > I haven't reviewed your compiler yet, and for that I apologize. But. You > need to make sure that when you compile, you build up a compile-time > environment, mapping symbols to locations -- if a variable is free, > lexically bound, or dynamically bound. When your compiler sees a lexical > binding, replace that identifier with a gensym, and add an entry to your > compile-time environment to map that identifier to that lexical gensym. > That way you will effectively be processing my example, which is > equivalent to yours, but perhaps clearer because the names have been > uniquified. Then your problems go away. This is how I was thinking about implementing the lexical-let semantics. To give more details: I want to keep track of identifiers that are lexically bound in the current scope while compiling as well as to what gensym they are, and then instead of the fluid-ref's just reference/set this gensym-identifier when I come across an access. It seems this is exactly what you describe above :) So, that's it with regards to messages from me :D Thanks for all your comments again, Daniel -- Done: Arc-Bar-Cav-Ran-Rog-Sam-Tou-Val-Wiz To go: Hea-Kni-Mon-Pri ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: Elisp lexical-let 2009-07-24 7:08 ` Daniel Kraft @ 2009-07-24 11:42 ` Andy Wingo 0 siblings, 0 replies; 18+ messages in thread From: Andy Wingo @ 2009-07-24 11:42 UTC (permalink / raw) To: Daniel Kraft; +Cc: Ken Raeburn, guile-devel Hi Daniel, On Fri 24 Jul 2009 09:08, Daniel Kraft <d@domob.eu> writes: >> It's actually fairly simple, imo. Alpha-equivalence says that >> (lexical-let ((x a)) x) is the same as (lexical-let ((y a)) y). (Note >> that this lexical-let corresponds to Scheme's let.) So your program is >> the same as: >> >>> (lexical-let ((y 2)) >>> y ; -> 2 >>> (foo) ; -> 1 >>> (setq y 3) >>> y ; -> 3 >>> (foo) ; -> 1 >>> (let ((x 4)) >>> x ; -> 4? >>> (foo) ; -> 4 >>> (setq x 5) >>> x ; -> 5 >>> (foo) ; -> 5 >>> ) ; end the let >>> y ; -> 3? >>> (foo) ; -> 4 >>> ) >>> x ; -> 4 >>> (foo) ; -> 4 > > Yes of course, my main question was how the inner let is handled, and > what dynamic values x will attain (the results of (foo)) -- and here's > this funny stuff that the inner let will be like lexical-let for those > variables already lexically bound. Wow, strange. What were they thinking. But if that's the deal, that's the deal... Andy -- http://wingolog.org/ ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2009-07-24 11:42 UTC | newest] Thread overview: 18+ messages (download: mbox.gz follow: Atom feed -- links below jump to the message on this page -- 2009-07-21 19:48 Elisp lexical-let Daniel Kraft 2009-07-21 21:46 ` Ken Raeburn 2009-07-22 9:11 ` Daniel Kraft 2009-07-22 13:00 ` Marijn Schouten (hkBst) 2009-07-22 19:24 ` Daniel Kraft 2009-07-23 15:24 ` Marijn Schouten (hkBst) 2009-07-23 16:13 ` Mark H Weaver 2009-07-23 20:53 ` Andy Wingo 2009-07-23 17:05 ` Daniel Kraft 2009-07-24 11:09 ` Marijn Schouten (hkBst) 2009-07-22 20:50 ` Ken Raeburn 2009-07-23 10:47 ` Daniel Kraft 2009-07-23 20:56 ` Andy Wingo 2009-07-24 6:50 ` Daniel Kraft 2009-07-23 20:49 ` Andy Wingo 2009-07-23 22:39 ` Andy Wingo 2009-07-24 7:08 ` Daniel Kraft 2009-07-24 11:42 ` Andy Wingo
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).