On Sat, 2002-03-30 at 21:41, Michel J Lambert wrote:
> > > Too late. I'm going there... :)
> > Good for you. I was hoping transformations could make it :)
> 
> Why didn't you chime in support before, then? I feel like Aaron and I are
> the only ones who are opinionated on this matter...

Hopefully, this has been a productive debate, and I'm not just sucking
up bits on everyone's disk. I tend to assume that when a small number of
people are debating on a mailing list that the others who are reading
are in agreement with one (or more?) of the stated opinions.

> > Here's something I was wondering. Say you wanted to write a pow() macro
> > (from a previous example) that would forward to C's pow() unless the
> > exponent was an integer, in which case it would optimize to many *'s. If
> > it was called like so:
> >
> > pow(2.718, 2 * 6 / 3)
> 
> Yeah, this is part of the problem of scheduling transformations. I believe
> it was mentioned to be NP-complete in the literature I read, but so are
> most compiler optimizations, and compilers usually use heuristics, so this
> problem shouldn't be unsolveable.
> 
> As Nick said in a different email, this particular constant-folding
> problem can be solved by using a bottom-up approach.
> 
> 2*pow(2.718,2*6);
> 
> 2*6=>12
> pow(2.718,12)=>constant
> 2*whatever=another constant


It sounds like you're proposing that a macro be executed the way the
peephole optimizations in GCC's RTL are executed (GCC is about the only
other compiler that I know as well as Perl, so pardon the forced
example). This has some merit, and I don't want to discount the idea.
However, I see the following problems that we would have to resolve:

1. The programmer is thinking in Perl (we hope!), but at the stage of
transformation that you're discussing, they will have to manipulate
Perl's internal form which may be structured counter-intuitively to a
Perl programmer.

2. As others have pointed out, a good deal of the magic of Perl is
performed at the syntax, not the grammar level (unlike, for example,
LISP).

In order to resolve these, I think we'd have to drop down to concrete
examples of implementation. What do you see this sort of macro looking
like?

> The problem comes in when we allow additions to these transformations. Say
> we have a simple arithmetic constant-folding transformation that handles
> the operators. The pow operator, when we 'use' it from some module, would
> import the pow() constant-folding transformation, or somesuch. It's a bit
> of a contrived example since pow() will probably be included by default,
> and not be imported, but I think the scenario is still a valid one.

We're speaking about how we manipulate Perl and do the same sorts of
things that the Perl compiler is doing, so I see your example as ideal
(if not practical).

So, let me see if I can get a handle on how your pow might work:

macro pow($a,$b) {
        if ($b.is_constant() && int($b) == $b) {
                my $func = sub { 1; };
                for(my $i = 0;$i<$b;$i++) {
                        $func = sub { $func.() * $a };
                }
                return $func;
        } else {
                return \&CORE::pow;
        }
}

I'm not 100% happy with the syntax, but I think it's pretty clear as an
example. First off, there's some things here which look like normal Perl
but aren't so they should be explained:

* $a and $b are not plain scalars. They are objects which represent the
operands to pow(). When evaluated in a numerical context, we try to peer
into $b and determine its value, but undef might be a valid response.
Thus, the test for is_constant.

* Since we're building an anonymous function during compilation, we
expect automatic inlining to take place after macro transformation. Thus
our return value for "pow(3,2)" would be:

    sub { (sub { (sub { 1; } ).() * $a}).() * $a}

But we expect Perl to transform this into:

    sub {1*$a*$a}
    
via inlining and then to inline this subroutine where the macro is being
evaluated. At that stage, Perl will have to root through the tree that
it's injecting and pull out any macro operand objects and replace them
with the variables that they represent. Thus "pow(3,2)" should become
"9" after macro expansion and optimization.

So, think this will handle your case of:

    my $y = 0;
    forall(my $x, @list, sub{$y += $x});
    
Though the handling of "my $x" gets a little hairy, and puts some
requirements on macro evaluation that may turn out to be cumbersome.

What I guess I'm saying is that I think I get it. So, what have we
bought? We're not using string handling to build code, and that makes me
happier. But, how much value does this add to the language, really?

> If we have these two different constant-folding transformations, no
> ordering of them can solve the one I just presented. They need to be
> applied in an interleaved manner.
> 
> In the worst case, after every transformation, the entire tree needs to be
> rechecked for every possible transformation. In this case, these
> transformations depend *only* on the nodes and subnodes, so we can limit
> the scope of where we have to re-check these constant-folding operations.
> If we define a constant-folding transformation category, then we can limit
> the checks to just those category of transformations.

Now I'm growing concerned. It sounds to me like macro authors would have
a very hard time determining exactly how their macros will be applied.

> PS: Yes, I know I write too much. :)

Your vision of the internals is interesting, but I'm lost without a
concrete example. There are just too many "Perls" that could come from
what you suggest.


Reply via email to