Prev: Books from the library of Erik Naggum
Next: G-List
From: Kenneth Tilton on 2 Jun 2010 05:08 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 2 Jun 2010 06:52 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 2 Jun 2010 12:33 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 2 Jun 2010 16:28
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 |