From: Tim Bradshaw on
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
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
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
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
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.