From: Peter Keller on
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?

Thank you.

-pete
From: His kennyness on
On 06/01/2010 10:56 PM, 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))

Where (in what Lisp) do you see that? It ain't how Lisp works. Did you
lose something in simplifying some other code that seems to work that way?

(defun hunh? () (let ((x 20)) (foo 10)))

....gives me a warning that x is unused, which it is. Unused, I mean.

kt



You code


>
> 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?
>
> Thank you.
>
> -pete

From: Peter Keller on
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.

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.

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

Thank you.

-pete
From: D Herring on
On 06/02/2010 12:40 AM, 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.
>
> 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.

There are common ways for a macro to get some of this information from
CL. Unfortunately, they were dropped from the ANSI standard and are
thus not uniformly supported. See for example
http://www.cs.cmu.edu/Groups/AI/html/cltl/clm/node102.html

On another level, be careful what you wish for.

Consider
(context
(macro-1
(macro-2 args-2)
(macro-3 args-3)
(macro-4 args-4)))

Should macro-3 be able to modify
* macro-1?
* the context of macro-1?
* macro-2 or macro-4?

How do such changes affect the compilation/evaluation of the other
macros? What ordering should be used? How would the compiler know no
other macros would rewrite the world?

This "down-only" view of the world exactly mirrors the view given to
normal functions. In both cases, dynamic variables and the like can
be used to create an API that passes information across stack frames.

- Daniel
From: Captain Obvious on
PK> Can a macro know something about the context into which it expands?

Yes, through environment objects.
Standard provides only very rudimentary means to work with them, but there
are implementation-specific extensions.

PK> Could the macro foo ever be smart enough to implement this statement:

PK> "If x is free and there are no other lexical variables named x
PK> available in the context into which I am expanding, then use the
PK> supplied argument binding, but if there is already a lexically
PK> available x,

It is possible to get this information from environment using
implementation-specific extensions.

PK> then just use that symbol's binding in favor of the supplied argument
PK> instead."

I think part "use that symbol's binding" just does not make sense --
bindings are completely out of scope of macros.
You can just use symbol as variable for same effect, though.

Something like that:

(defmacro foo (x &environment env)
(if (eq :lexical (sb-cltl2:variable-information 'x env))
`(+ x 10)
`(+ ,x 10)))

PK> With another variable in the lexical space around it, notice how
PK> the argument x gets dropped in favor of the lexical binding x:

PK> (macroexpand '(let ((x 20)) (foo 10))) -> (let ((x 20)) (+ 20 10))

Why not (let ((x 20)) (+ x 10)) ?

PK> the variable namespace and into things like "If I am in a parse tree
PK> that looks like this, expand my body in this manner."

This makes no sense from point of view of Common Lisp macroexpansion model.
Macros are meant to be modular, they should be obvlivious of the context.

PK> If I write my own code walker, I can do this, but can I use Lisp's
PK> instead?

There is a legal way of communication between different levels of macros --
through macroexpansion.
Upper-level macros can inject new macros into environment through macrolet,
and lower-level macros can call them via macroexpand.

I think you can do a lot through this mechanism, you just need to structure
it in a different way.

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