[1] That one's kind of interesting actually. If the macro is called right upon parsing it, it will be called before it's done compiling it. Which is a problem. Is there a way to get around this, because recusive macros are useful (as demonstrated above).
On Sat, Aug 02, 2003 at 01:18:01PM -0600, Luke Palmer wrote:
: While we seem to be on the subject of hashing out macro semantics, : here's a question I've had awhile. : : What do macros do about being passed variables? : : Let's say I make a C<square> macro: : : macro square ($x) { : { $x * $x } : } : : And then I have code. : : my $var = 10; : print square $var; : : Does that turn that into (at compile time): : : print($var * $var); : : Or does it use the compile time value of $x, turning it into: : : print(undef * undef); : : I would hope the former.
It's the former. The block is essentially inlined.
: However, what about this compile-time : integral power macro[1]? : : macro power ($x, $p) { : if $p > 0 { : { $x * power($x, $p-1) } : } : else { : { 1 } : } : } : : That would hopefully turn: : : my $var = 10; : print power $var, 4; : : Into : : print($var * $var * $var * $var * 1);
Nope. $x and $p are syntax trees. If you want compile-time evaluation you'd have to do something explicit in there to evaluate $p:
macro power ($x, $p) { my $count = $p.run(); if $count > 0 { $count--; { $x * power($x, $count) } } else { { 1 } } }
That might be reducable to:
macro power ($x, $p is run) { if $p > 0 { $p--; { $x * power($x, $p) } } else { { 1 } } }
But you can't decrement $p inside the block, or it just becomes part of the inlined code.
: But what about : : my $var = 10; : my $ex = 4; : print power $var, $ex;
Depends on how power is written. Can't have it both ways unless power is written to finesse it somehow.
: [1] That one's kind of interesting actually. If the macro is called : right upon parsing it, it will be called before it's done compiling : it. Which is a problem. Is there a way to get around this, because : recusive macros are useful (as demonstrated above).
I suppose one could defer the expansion of a nested macro till it's called for real. That might mean that we need an explicit keyword on the block though to suppress immediate expansion:
macro power ($x, $p is run) { if $p > 0 { $p--; template { $x * power($x, $p) } } else { template { 1 } } }
Alternately, we just defer the expansion of any declared but undefined macro till it is defined somehow. That would presumably handle mutually recursive macros even.
Those are both hard. Unless someone volunteers to implement it, we could just say that you have to write a helper sub if you want recursion.
Macros are passed syntax trees as arguments, but return coderefs?
That's... odd.
I would expect that a macro would be expected to *return* a syntax tree... which could then undergo (more) macro-expansion.
Sortof like how in lisp, a macro recieves lists as arguments (those lists being un-evaluated code) and then returns a list, which then has more macro expansion done on it, and then gets parsed and evaluated.
-- $a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca );{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "$@[$a%6 ]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}
> Larry Wall wrote: > [snip] > > Nope. $x and $p are syntax trees.
> <blink>
> Macros are passed syntax trees as arguments, but return coderefs?
> That's... odd.
> I would expect that a macro would be expected to *return* a syntax > tree... which could then undergo (more) macro-expansion.
Keep in mind, a macro can return a lot of things to get a lot of different behavior. It can return a string which will be inserted in the input stream in place of the macro call; it can return a closure which will be inserted into the generated code at that point. Along the same lines, you can return a syntax tree to be inserted into the, um, syntax tree at that point.
Perhaps with C<template>, as Larry mentioned earlier (though I'm not sure that he intended this meaning):
template { $x + 1 }
Would return a syntax tree for $x + 1. Obviously, the syntax tree would have to be closure-like, because the string '$x' isn't enough to represent this $x. It would have to keep some sort of reference to the lexical... or lexical table entry... or something.
And indeed, that would solve the macro recursion bit, if the just-inserted syntax tree underwent more macro expansion.
> Sortof like how in lisp, a macro recieves lists as arguments (those > lists being un-evaluated code) and then returns a list, which then has > more macro expansion done on it, and then gets parsed and evaluated.
> -- > $a=24;split//,240513;s/\B/ => /for@@=qw(ac ab bc ba cb ca > );{push(@b,$a),($a-=6)^=1 for 2..$a/6x--$|;print "$@[$a%6 > ]\n";((6<=($a-=6))?$a+=$_[$a%6]-$a%6:($a=pop @b))&&redo;}
A partial evaluator simplifies a function with respect to some of its inputs, if possible. This can be quite powerful: If P is a partial evaluator, I an interpreter, and C some code, the P(I,C) compiles C (in a rudimentary sort of way) and P(P,I) produces a compiler. But code has to be written with an eye to making it possible to simplify it, otherwise you just get the original code back.
In theory you could write one as a perl6 macro, although it would be more convenient if there was someway of obtaining the syntax tree of a previously defined function other than quoting it (unless I've missed that?). But I confidently predict that no-one with write a useful partial evaluator for perl6. The language is simply too big.
Alex Burr writes: > In theory you could write one as a perl6 macro, although it would be > more convenient if there was someway of obtaining the syntax tree of a > previously defined function other than quoting it (unless I've missed > that?).
There is a large class of cool optimizations possible when you combine notifications with storing the syntax tree at runtime, so I think it will be possible to get the syntax tree of a previously defined function. Probably just a method on Code objects.
> But I confidently predict that no-one with write a useful > partial evaluator for perl6. The language is simply too big.
Then again, there are some very talented people with a lot of free time in the Perl community; I wouldn't count it out.
> A partial evaluator simplifies a function with respect to some of its > inputs, if possible. This can be quite powerful: If P is a partial > evaluator, I an interpreter, and C some code, the P(I,C) compiles C > (in a rudimentary sort of way) and P(P,I) produces a compiler. But > code has to be written with an eye to making it possible to simplify it, > otherwise you just get the original code back.
> In theory you could write one as a perl6 macro, although it would be > more convenient if there was someway of obtaining the syntax tree of a > previously defined function other than quoting it (unless I've missed > that?). > But I confidently predict that no-one with write a useful partial > evaluator for perl6. The language is simply too big.
As it is currently defined the default "is parsed" trait includes evaluating the arguments before the marco is called, so the above macro doesn't do what you want with out adding some magic.
One way to do what you want is to use a string returning macro with an "is parsed" trait that return the unevaluated args as strings and then concat up the string for the expression you want.
Another possibility is a built-in trait orthoginal to "is parsed" that turns off argument evaluation and allow the args to be passed in as syntax trees, allowing the macro to built the syntax tree to be returned.
I imagine that by the time all is done there will be a whole set if trait definitions to make various types of macros easy to do. Which brings us back to the need for a way to bundle up a set of traits and give it a name.
Luke Palmer <fibon...@babylonia.flatirons.org> writes: > Alex Burr writes: >> In theory you could write one as a perl6 macro, although it would be >> more convenient if there was someway of obtaining the syntax tree of a >> previously defined function other than quoting it (unless I've missed >> that?).
> There is a large class of cool optimizations possible when you combine > notifications with storing the syntax tree at runtime, so I think it > will be possible to get the syntax tree of a previously defined > function. Probably just a method on Code objects.
I'll be very disappointed if you can't get the syntax tree at runtime, though I have the feeling that it might require a compilation switch of some sort.
On Mon, 15 Sep 2003, Piers Cawley wrote: > Luke Palmer <fibon...@babylonia.flatirons.org> writes:
> > Alex Burr writes: > >> In theory you could write one as a perl6 macro, although it would be > >> more convenient if there was someway of obtaining the syntax tree of a > >> previously defined function other than quoting it (unless I've missed > >> that?).
> > There is a large class of cool optimizations possible when you combine > > notifications with storing the syntax tree at runtime, so I think it > > will be possible to get the syntax tree of a previously defined > > function. Probably just a method on Code objects.
> I'll be very disappointed if you can't get the syntax tree at > runtime, though I have the feeling that it might require a > compilation switch of some sort.
The syntax tree will be stored by default, though it will be strippable from the bytecode files for space and/or paranoia reasons.
: >fibon...@babylonia.flatirons.org (Luke Palmer) writes: : > : > : >>I would hope the former. However, what about this compile-time : >>integral power macro[1]? : >> : >> macro power ($x, $p) { : >> if $p > 0 { : >> { $x * power($x, $p-1) } : >> } : >> else { : >> { 1 } : >> } : >> }
Note that you have to explicitly return a closure, otherwise they look like bare blocks. Which might accidentally do what you want, if $x knows how to be a number, and any return value that's not a closure gets coerced to string. But it wouldn't be doing what you think it's doing.
: >The complete answer to this would be partial evaluation. Partial : >evaluators exist for langauges such as lisp, ML, and even C. See : >http://www.dina.dk/~sestoft/pebook/pebook.html
I tend to think of it inside out from that, in terms of deferred evaluation of the parts that are known to be still undefined. Note that we can know how to parse a macro from its declaration even before we know how to call its body, so we can tell easily when we hit power() that it can parse but can't run yet.
: >A partial evaluator simplifies a function with respect to some of its : >inputs, if possible. This can be quite powerful: If P is a partial : >evaluator, I an interpreter, and C some code, the P(I,C) compiles C : >(in a rudimentary sort of way) and P(P,I) produces a compiler. But : >code has to be written with an eye to making it possible to simplify it, : >otherwise you just get the original code back. : > : >In theory you could write one as a perl6 macro, although it would be : >more convenient if there was someway of obtaining the syntax tree of a : >previously defined function other than quoting it (unless I've missed : >that?). : >But I confidently predict that no-one with write a useful partial : >evaluator for perl6. The language is simply too big.
On Fri, Sep 12, 2003 at 12:49:47PM -0700, Mark A. Biggar wrote:
: As it is currently defined the default "is parsed" trait includes : evaluating the arguments before the marco is called, so the above : macro doesn't do what you want with out adding some magic.
I don't think it evaluates unless you tell it to explicitly.
: One way to do what you want is to use a string returning macro with : an "is parsed" trait that return the unevaluated args as strings and : then concat up the string for the expression you want.
Shouldn't be a problem--the arguments are pattern match result objects that can behave as strings if you want them to.
: Another possibility is a built-in trait orthoginal to "is parsed" : that turns off argument evaluation and allow the args to be passed : in as syntax trees, allowing the macro to built the syntax tree : to be returned.
That's the default. You'd need to use .run or some such to execute a chunk of syntax tree. Remember that the definition of eval($str) is something like $str.parse.run. I suppose evalharder($str) would be $str.parse.optimize_the_heck_out_of.run. :-)
: I imagine that by the time all is done there will be a whole set : if trait definitions to make various types of macros easy to do. : Which brings us back to the need for a way to bundle up a set of : traits and give it a name.
If we work it right, that's just called a "module". I think of traits as funny class definitions, and we're already planning to be able to bundle related classes in a module. Could go so far as to have derived modules that can retarget an entire collection of classes in parallel.