From: Tim Bradshaw on 29 Jan 2010 08:54 On 2010-01-29 04:38:32 +0000, refun said: > Not really, but it's not an impossible situation even in C: > If you got got the compiler to generate a local environment for the function by > forcing it to stack allocate each variable, and make such environment/variable > location(on the stack) maps and generated a function location map, and if > some_expr_eval_lib_function is made in such a way that it can access such info, > it would be entirely possible for it to return 3. I doubt there is much use of > such costly machinery unless you want the embedded language to have full access > to C. Isn't that basically saying "if you'd like not to have a compiler".
From: Pascal J. Bourguignon on 29 Jan 2010 09:00 refun <refun(a)nospam.gmx.com> writes: > In article <20100128201032.389(a)gmail.com>, kkylheku(a)gmail.com says... >> >> On 2010-01-29, refun <refun(a)nospam.gmx.com> wrote: >> > When I started learning Common Lisp some half a year ago, I was puzzled why >> > it's not possible EVAL or COMPILE forms within a lexical environment of one's >> > choosing. Someone who just started learning Lisp and who doesn't understand >> > lexical and dynamic scope may expect (let ((y 1) (x 2)) (eval '(+ x y))) to >> > return 3, instead of an error. (assuming x and y are not declared special). >> >> Did you have experience in other programming languages? > > C, x86 asm, C#/Java, O'Caml, some Scheme and some scripting languages. > >> In C and its ilk, would you expect this to fetch 3 into z? >> >> { >> int x = 1, y = 2; >> int z = some_expr_eval_lib_function("x + y"); >> } > > Not really, but it's not an impossible situation even in C: Actually not. typedef struct { char* name; int value} binding; #define lengthof(vector) (sizeof(vector)/sizeof(vector[0])) { int x = 1, y = 2; binding b[]={{"x",x},{"y",y}}; int z = some_expr_eval_lib_function(bindings,lengthof(bindings),"x + y"); } See for example: http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/c0a662dedc45ef51/712eb6000693dd93?q=eval+defmacro+lambda+lexical+group:comp.lang.lisp#712eb6000693dd93 (notably Kent's answer). Also, your example is misleading. For (+ x y), you can easily use: (let ((x 1) (y 2)) ((lambda (x y) (+ x y)) x y)) instead of eval (which can be expanded by a macro call such as: (eval-with-lexical-variables (x y) (+ x y)) What you mean is to be able to evaluate random forms: (let ((a 42) (z 99)) (let ((x 1) (y 2)) (eval-with-bindings (bindings a z x y) (read)))) Now, a question is how the list of the visible lexical variables could be infered automatically. This could be done using implementation specific stuff as you did, or by shadowing all lexically binding operators and implementing the needed bookkeeping in replacing macros. However, once you want to allow things like (READ) to get the form, you may also want to prevent free access to the whole lexical scope! Perhaps you really wanted only: (let ((a 42) (z 99)) (let ((x 1) (y 2)) (eval-with-bindings (bindings x y) (read)))) So there is no point in tinkering with the real lexical environment. -- __Pascal Bourguignon__
From: smh on 30 Jan 2010 00:15 On Jan 28, 7:20 pm, refun <re...(a)nospam.gmx.com> wrote: > When I started learning Common Lisp some half a year ago, I was puzzled why > it's not possible EVAL or COMPILE forms within a lexical environment of one's > choosing. Coincidentally I needed the capability to inject some forms inside a large compiled function, compiling them at run time in the correct lexical environment, as if the forms had been present literally when the containing function was defined. I won't go into the need for that code, but was able to build the facility on top of the (semi)portable environment facility in Allegro, and the ensuring- compiled-body macro was added as a patch to Allegro last October. The intention is that it correctly captures all four of the CL lexical binding spaces and generally achieves execution efficiency not to different from regularly compiled code, at least for its intended uses. As the current thread posits, solving this problem is an interesting study of CL semantics, so I wrote up a description of the rewriting the macro has to do. It was published as a "Tech Corner" article here: <http://www.franz.com/support/tech_corner/ensure-comp101409.lhtml> The rewriting details are not completely portable, of course, because they assume certain things about the implementation, e.g. that the compiler processes compiler-macros. Anyway, you should find it interesting and relevant. (By the way, I notice a typo in the article that I will have fixed next week. There is a single quote missing before the lambda in the block example.)
From: refun on 30 Jan 2010 05:14 In article <87ljfh3tb3.fsf(a)informatimago.com>, pjb(a)informatimago.com says... > > refun <refun(a)nospam.gmx.com> writes: > > > In article <20100128201032.389(a)gmail.com>, kkylheku(a)gmail.com says... > >> > >> On 2010-01-29, refun <refun(a)nospam.gmx.com> wrote: > >> > When I started learning Common Lisp some half a year ago, I was puzzled > >> > why > >> > it's not possible EVAL or COMPILE forms within a lexical environment of > >> > one's > >> > choosing. Someone who just started learning Lisp and who doesn't > >> > understand > >> > lexical and dynamic scope may expect (let ((y 1) (x 2)) (eval '(+ x y))) > >> > to > >> > return 3, instead of an error. (assuming x and y are not declared > >> > special). > >> > >> Did you have experience in other programming languages? > > > > C, x86 asm, C#/Java, O'Caml, some Scheme and some scripting languages. > > > >> In C and its ilk, would you expect this to fetch 3 into z? > >> > >> { > >> int x = 1, y = 2; > >> int z = some_expr_eval_lib_function("x + y"); > >> } > > > > Not really, but it's not an impossible situation even in C: > Actually not. > > typedef struct { char* name; int value} binding; > #define lengthof(vector) (sizeof(vector)/sizeof(vector[0])) > > { > int x = 1, y = 2; > binding b[]={{"x",x},{"y",y}}; > int z = some_expr_eval_lib_function(bindings,lengthof(bindings),"x + y"); > } > > See for example: > > http://groups.google.com/group/comp.lang.lisp/browse_thread/thread/c0a662dedc > 45ef51/712eb6000693dd93?q=eval+defmacro+lambda+lexical+group:comp.lang.lisp#71 > 2eb6000693dd93 > > (notably Kent's answer). > > That's useful if one wants to only pass specific variables and functions to the code that is about to be eval'd. I'd suspect in practice it may well be enough. > > Also, your example is misleading. For (+ x y), you can easily use: > > (let ((x 1) > (y 2)) > ((lambda (x y) (+ x y)) x y)) > > instead of eval (which can be expanded by a macro call such as: > > (eval-with-lexical-variables (x y) (+ x y)) > > Yes, however it does not allow user-generated forms. If a form is constant, it's unlikely you'll want to EVAL it at runtime. > What you mean is to be able to evaluate random forms: > > (let ((a 42) > (z 99)) > (let ((x 1) > (y 2)) > (eval-with-bindings (bindings a z x y) (read)))) > > > Now, a question is how the list of the visible lexical variables could > be infered automatically. This could be done using implementation > specific stuff as you did, or by shadowing all lexically binding > operators and implementing the needed bookkeeping in replacing macros. > I think there's a third method which would involve collecting(flatten?) all symbols in the form to be eval/compile'd and then checking if it exists in the current lexical environment using that "Environment Access"(or CLTL2's environments) library which is supposed by some implementations. I'm a bit unsure about how one would go about "shadowing all lexically binding operators" as you'd still need to know what they are, or did I misunderstand your idea? > > However, once you want to allow things like (READ) to get the form, > you may also want to prevent free access to the whole lexical scope! > There may be other use scenarios besides READ, such as dynamically generated code by some ??? to CL compiler. > Perhaps you really wanted only: > > (let ((a 42) > (z 99)) > (let ((x 1) > (y 2)) > (eval-with-bindings (bindings x y) (read)))) > > So there is no point in tinkering with the real lexical environment. As I mentioned before, when I wrote the macro, I did not have a particular use scenario in mind, it was mostly done as an exercise in macro writing, however that's not to say that I might never end up using it if a situation arises where it's truly necessary.
From: refun on 30 Jan 2010 05:16 In article <e9013afa-b286-4dcf-a5fc-e0b2329de8d0(a)b7g2000pro.googlegroups.com>, shaflich(a)gmail.com says... > > As the current thread posits, solving this problem is an interesting > study of CL > semantics, so I wrote up a description of the rewriting the macro has > to do. It > was published as a "Tech Corner" article here: > > <http://www.franz.com/support/tech_corner/ensure-comp101409.lhtml> > > The rewriting details are not completely portable, of course, because > they assume > certain things about the implementation, e.g. that the compiler > processes > compiler-macros. Anyway, you should find it interesting and relevant. > > (By the way, I notice a typo in the article that I will have fixed > next week. > There is a single quote missing before the lambda in the block > example.) That's quite an interesting article, however some parts were not entirely clear to me, such as macrolet's expansion: 1) It uses a variable named rest, but where is that defined? 2) In which environment does the local macro expand? The outer environment, the inner one or a combination of both? I also noticed that local variables expand to SYMBOL-MACROLET's which point to the locative of the original variable, which is more or less the same idea that I used in my macro, and it does not exhibit the problem I was worrying about: someone declaring a symbol macro special, however that can be simply prevented by wrapping the body in a PROGN, which means the issue I was worrying about does not really exist. I'll have to rewrite my compile/ce macro, as the current design has a major flaw which makes it non-reentrant and will might even prevent the gc from collecting data present in the special gensyms as they keep being referenced in the original function body (The issue is not present in eval/ce as that uses locally special symbols to pass data). I've also not considered blocks/tagbodies yet.
First
|
Prev
|
Next
|
Last
Pages: 1 2 3 Prev: PLT Scheme v4.2.4 Next: Concatenating adjacent strings in a list |