From: Kenneth Tilton on
Peter Keller wrote:
> His kennyness <kentilton(a)gmail.com> wrote:
>> Where (in what Lisp) do you see that? It ain't how Lisp works.
>
> I don't see this functionality in any Lisp at all. But it doesn't mean there
> wasn't some dark hidden corner in Lisp which could do this and I just didn't
> know about it.

Oh, I see, that was a "what if?".

>
> I'm sketching a lisp-like programming language where homoiconicity is taken to
> the next level and a "macro" can look into the annotated AST in which the macro
> is expanding in addition to the sub-AST passed to the macro.
>
> Lisp macros can do this somewhat in that a macro can view/manipulate the syntax
> tree of forms passed to it, but only "downward" in the AST towards the leaves.
> I want to look and manipulate "upward" and in other dimensions, like symbol
> tables, as well.

The two "x"s would still be different. One bound to the foo argument,
the other in the outer scope. Even a normal macro can have two x's, one
a parameter or local variable, another a captured lexical x, but they
would remain distinct and shadow one another only if the macro author
code up a shadowing -- Lisp would have no way to do that, and I have
some confidence one would never want this.

Are we getting ahead of ourselves? Lisp does that to people.

kt

>
> It seems, though, that I'll have to implement a codewalker for it.

The problem is not not having a way to do what is wanted, it is wanting
it. Is there a real use case for this? ie, something not called foo?

kt
From: Pascal Costanza on
On 02/06/2010 04:56, Peter Keller wrote:
> Hello,
>
> Can a macro know something about the context into which it expands?
>
> An example, suppose I have:
>
> (defmacro foo (x) `(+ ,x 10))
>
> Could the macro foo ever be smart enough to implement this statement:
>
> "If x is free and there are no other lexical variables named x available in the
> context into which I am expanding, then use the supplied argument binding, but
> if there is already a lexically available x, then just use that symbol's
> binding in favor of the supplied argument instead."
>
> An example (paraphrasing):
>
> Normally, what'd you'd expect:
>
> (macroexpand '(foo 10)) -> (+ 10 10)
>
> With another variable in the lexical space around it, notice how
> the argument x gets dropped in favor of the lexical binding x:
>
> (macroexpand '(let ((x 20)) (foo 10))) -> (let ((x 20)) (+ 20 10))
>
> Of course, one can design much more complex policies about how the expansion
> must happen given the context of the expansion going beyond the variable
> namespace and into things like "If I am in a parse tree that looks like this,
> expand my body in this manner."
>
> If I write my own code walker, I can do this, but can I use Lisp's instead?

What you want would be relatively easy to achieve if you can ask the
user of your macro to use only your own binding forms. Something as follows:

(my-let ((x 20)) (foo 10))

Then my-let could insert information into the lexical environment by way
of macros or symbol macros, which can be retrieved in foo using an
&environment parameter and macroexpand. You can find examples how to
achieve this here:
http://www.lispworks.com/documentation/HyperSpec/Issues/iss066_w.htm -
this is a discussion how compiler-let can be replaced with such
techniques, which was an important argument for eventually dropping
compiler-let from Common Lisp.


Pascal

--
My website: http://p-cos.net
Common Lisp Document Repository: http://cdr.eurolisp.org
Closer to MOP & ContextL: http://common-lisp.net/project/closer/
From: Thomas A. Russ on
Peter Keller <psilord(a)cs.wisc.edu> writes:

> Hello,
>
> Can a macro know something about the context into which it expands?
>
> An example, suppose I have:
>
> (defmacro foo (x) `(+ ,x 10))
>
> Could the macro foo ever be smart enough to implement this statement:
>
> "If x is free and there are no other lexical variables named x
> available in the context into which I am expanding, then use the
> supplied argument binding, but if there is already a lexically
> available x, then just use that symbol's binding in favor of the
> supplied argument instead."

As others have pointed out, this is (maybe) available through the
environment argument, but is not portable, since that information is not
standardized. You would have to use implementation-specific extensions.

The larger question, though, is whether this is really a good idea. It
seems that there are a lot of potential problems with it, one of which
is that introducing such contextual information can make the use of the
macro highly unpredictable to users. That makes it really tough to use
properly for programming.

This can, perhaps, be mitigated somewhat by using Pascal Costanza's
suggestion of introducing your own binding forms (or more generally,
your own containing macro form) that establishes information that you
use. Ideally this would be hidden information so that you don't end up
with spurious variable capture forms.

> An example (paraphrasing):
>
> Normally, what'd you'd expect:
>
> (macroexpand '(foo 10)) -> (+ 10 10)
>
> With another variable in the lexical space around it, notice how
> the argument x gets dropped in favor of the lexical binding x:
>
> (macroexpand '(let ((x 20)) (foo 10))) -> (let ((x 20)) (+ 20 10))

The real problem lies when you start getting things that are a lot more
complicated. After all, imagine the following example and the
tremendous confusion and debugging problems it would entail:

(let ((x 20))
.... ;; lots of code
(let ((y 30))
(do-something-to (foo y))))

The expansion of (foo y) into (+ 20 10) would be rather surprising to
most users, because of the hidden variable capture that is occurring.

Now, that said, I have often wished for more information about the
environment, and in particular the compiler optimization settings in
order to be able to change macro expansions. For example, it would be
nice to be able to write macros that could expand differently, say based
on SPEED, SAFETY and DEBUG settings of the compiler switches.

--
Thomas A. Russ, USC/Information Sciences Institute
From: Peter Keller on
Kenneth Tilton <kentilton(a)gmail.com> wrote:
> The problem is not not having a way to do what is wanted, it is wanting
> it. Is there a real use case for this? ie, something not called foo?

Ok, here is a working, though incomplete since I didn't deal with lexical
poisoning, example which contains part of what it is I want to do.

(defmacro upto-gen (&rest lst)
(let ((m 10)
(result nil))
(tagbody
again
(labels ((upto (l)
(cond
((equalp (car l) :five)
(setf m 5)
(setf result nil)
(go again))

((null l)
nil)

((< (car l) m)
(push (car l) result)
(upto (cdr l))))))
(upto lst)))

(list 'quote (nreverse result))))

It works like this:

* (upto-gen 1 2 3 4 5)

(1 2 3 4 5)
* (upto-gen 1 2 3 4 5 6 7 8 9 10 11 12 13)

(1 2 3 4 5 6 7 8 9)
* (upto-gen 1 2 3 4 5 6 7 8 9 :five 10 11)

(1 2 3 4)

The reason I want to do this is because I'm performing a sketch of a
meta-language which one would use to describe a programming language, its
compiler, the debugging information, and the debugger. When you compile the
meta-language, the compiler and debugger for the language fall out of the
macros.

An example like the above might be dead code elimination. :five could represent
some identification of a path in the code I'm walking that I can leave out so I
should retry the walk with the new knowledge.

In using this, one would pass a set of forms to a macro which would produce a
graph that is more optimized than the original one. The resultant output is
itself lisp that is then given to the compiler to be compiled normally--I'd get
rid of the list construct at the bottom and just let it go to the compiler.

What I'm trying to figure out is how this and other macros like it would
compose with each other since I can pass the tagbody name to a lower macro
which can force execution back to an upper one and change its behavior.

This example doesn't exhibit rewriting a macro body or the syntax of the
calling macro and calling it again, just passing some information between them.
The second part is where I don't know if lisp itself could do it and I would
have to make something more explicit.

What I'm doing will very well go against the grain of Lisp of the sanity of
lisp hackers, however, Lisp is the only game in town which will even let me
try!

Thank you.

-pete


First  |  Prev  | 
Pages: 1 2
Prev: Books from the library of Erik Naggum
Next: G-List