Re: Topicalizers: Why does when's EXPR pay attention to topicalizer r egardless of associated variable?
On Tue, 2002-03-26 at 13:19, Larry Wall wrote: > Aaron Sherman writes: > : Ok, so am I to take it that you could say: > : > : FOO: for @x { > : BAR: for @y { > : print $FOO::_; > : } > : } > > Er, I don't think so. > > : Or is OUTER a special-case label? > > It's a special case like MY::, and somewhat ugly to discourage you from > using it when you should probably be naming your loop variables. That's too bad. If OUTER could only jump up one level, it's going to be painful. For example, when you take your example, and go back to modify the code. It may not be glaringly obvious that adding a middle loop will cause the code to break. We're treading dangerously close to putting TCL's upvar into Perl, which would be a crime against God and man. However, I think you can have a reasonable syntax for what you want. Use labels as namespaces via a special syntax. Then, scope labels lexically (already the case?), so you can't use this syntax to get at callers' namespaces, etc. Here's an example syntax: FOO: for @x { BAR: for @y { my $foo_under FOO:= $_; print $_, $foo_under; } } This takes visual advantage of ":=" as the aliasing syntax while maintaining the look of a label. Of course, that's just one syntax possibility. The concept here is accessing lexically-scoped namespaces via labels. Given this, you cannot break the code by adding a middle loop, and it's obvious exactly what was intended. The other syntax you could use would be less generic, but would really nail home the idea of topic to the programmer: FOO: for @x { BAR: for @y { my $foo_under is topicof(FOO); print $_, $foo_under; } } I don't like this as much, but I see the benefits. > : Personally, I've always prefered this syntax: > : > : for @x {\ > : for @y { | > : print;<-/ > : } > : } > : > : Which is visually appealing and raises coding style arguments to a whole > : new level. > > Hmm, tempting. Ok, I'll get right on ascii_art_toke.c. I thought I'd never get a chance to bring machine vision into the Perl core! ;-)
Re: Perl6 Macros
On Tue, 2002-03-26 at 16:26, Michel J Lambert wrote: > An example of where variable capture is needed is: > macro println ($a) { > return <<"EOF"; > print $a; > print "\n"; > EOF > } > for my $b (1..100) { > println $b; > } Ok, I don't get it. I'm willing to concede that I'm dense, but I need to understand how. This looks to me like: sub println ($a) { print $a, "\n"; } for my $b (1..100) { println $b; } And, if we inline the sub, the only difference will be...? Your example seems to involve no variable capture at all, in fact, just passing parameters to a macro. See below > Personally, I'm at a loss for how macros will fit seamlessly in Perl 6. > The examples above return a string, instead of real code (to make it > easier to see how the interpolation works.) The code passes in a block of > code, which magically gets interpolated back into a string as its original > code form. I *can* see some advantage in: macro mygrep ($code is macroblock, *@list) { my @newlist = (); for @list { push @newlist, $_ if $code.(); } return @newlist; } @x = mygrep {/\S/} $fh.getlines(); where no code reference is ever created. It could be abused mercilessly, but I can see the massive savings in performance that we would reap, especially when translating/compiling this code for native or JIT execution. This is because we don't have to fire a function call each time we execute the block. But, perhaps this is too syntax-heavy. Maybe something simpler: sub mygrep ($code is inline, *@list) { my @newlist = (); for @list { push @newlist, $_ if $code.(); } return @newlist; } @x = mygrep {/\S/} $fh.getlines(); Now you put it in the compiler's hands to determine if a code reference should be generated or not. Access to $_ is the only thing that is in question here, and I don't have a good answer off the top of my head. It would be very interesting to see how sub mymap ($code is inline, *@list) { my @newlist = (); for @list { push @newlist, $code.(); } return @newlist; } @x = mymap {mygrep {$_} split //, $_} $fh.getlines(); would behave. Possibly quite efficient. > Other things which the above 'forintlist' example used was the ability to > send an arbitrary structure to the macro, and have it be matched against > the parameter list for the macro. This allows one more flexibility in > passing parameters to a macro, as they don't need to be a straight out > list/array, but can be more complicatged structures, which are > automagically matched. If this were in perl 6, regular array/list argument > passing could be a simple case of a more complex argument/parameter > passing structure. I think your ideas here are good. If a general mechanism could be found for the syntax and deemed valuable enough to add, I'd be all for it. However, is it really macro-specific or should it be part of the function call syntax in general?
Re: Topicalizers: Why does when's EXPR pay attention to topicaliz er r egardless of associated variable?
Aaron Sherman writes: : Here's an example syntax: : : FOO: for @x { : BAR: for @y { : my $foo_under FOO:= $_; : print $_, $foo_under; : } : } I think if we have to go through contortions to get at the outer topic by name, it's better to just name the variable on the outer loop in the first place. Adding -> $varname to the outer loop is safe, because it doesn't change the semantics of topicality--now that we changed the rule so that $_ is always aliased to the topic regardless of whether it's aliased to an explicit variable name. Larry
Re: Topicalizers: Why does when's EXPR pay attention to topicaliz er r egardless of associated variable?
Larry Wall writes: > I think if we have to go through contortions to get at the outer topic > by name, it's better to just name the variable on the outer loop in the > first place. Adding -> $varname to the outer loop is safe, because it > doesn't change the semantics of topicality--now that we changed the > rule so that $_ is always aliased to the topic regardless of whether > it's aliased to an explicit variable name. > > Larry This seems to argue against OUTER:: -- Eric J. Roode[EMAIL PROTECTED] Senior Software Engineer, Myxa Corporation @_=unpack "C*",qq;\cw22(D\coF?!%\$&D\x1e=B\cyB'\cu"\cy=B\; $>=0; ;$=-=$=; push (@^A,$_[$=++]+$_),$^A[$=-1]=~s+\d[^&0.=^&1].+$&-ord e+e foreach map{unpack 'C'x8,$_}(\getpwuid $>)[0,2,5]; print pack('C*',@^A),"\n";
Re: Perl6 Macros
At 10:27 AM -0500 3/27/02, Aaron Sherman wrote: >I *can* see some advantage in: > > macro mygrep ($code is macroblock, *@list) { > my @newlist = (); > for @list { > push @newlist, $_ if $code.(); > } > return @newlist; > } > @x = mygrep {/\S/} $fh.getlines(); > >where no code reference is ever created. It could be abused mercilessly, >but I can see the massive savings in performance that we would reap, >especially when translating/compiling this code for native or JIT >execution. This is because we don't have to fire a function call each >time we execute the block. Just out of curiosity, is there anything macros (in the Lisp sense) can do that source filters can't? -- Dan --"it's like this"--- Dan Sugalski even samurai [EMAIL PROTECTED] have teddy bears and even teddy bears get drunk
Re: Topicalizers: Why does when's EXPR pay attention to topicaliz er r egardless of associated variable?
Eric Roode writes: : Larry Wall writes: : > I think if we have to go through contortions to get at the outer topic : > by name, it's better to just name the variable on the outer loop in the : > first place. Adding -> $varname to the outer loop is safe, because it : > doesn't change the semantics of topicality--now that we changed the : > rule so that $_ is always aliased to the topic regardless of whether : > it's aliased to an explicit variable name. : > : > Larry : : This seems to argue against OUTER:: Yeah, but we need to have OUTER:: anyway if we want to support my $foo = $OUTER::foo; And we need that because, unlike in Perl 5, the new $foo is introduced immediately, not at the end of the statement. And the reason for that is so that something like my &foo = sub { foo() } can recognize that recursion is supposed to happen. (We didn't have to deal with that in Perl 5 because we didn't have lexical subroutines.) Anyway, as I said earlier, I made $OUTER::foo ugly on purpose. I particularly want people to start to gnash their teeth when they type $OUTER::OUTER::foo, because it means they're being lazy in the wrong way. Larry
Re: Perl6 Macros
Dan Sugalski writes: : Just out of curiosity, is there anything macros (in the Lisp sense) : can do that source filters can't? Avoid reparsing the language themselves? Larry
Re: Perl6 Macros
On Wed, 2002-03-27 at 11:31, Dan Sugalski wrote: > At 10:27 AM -0500 3/27/02, Aaron Sherman wrote: > > macro mygrep ($code is macroblock, *@list) { > > my @newlist = (); > > for @list { > > push @newlist, $_ if $code.(); > > } > > return @newlist; > > } > > @x = mygrep {/\S/} $fh.getlines(); This just brought something to mind when I re-read it. I was thinking about how this would transform back into Perl, and I thought... gee, you can't do that easily because you're taking the result of a block, and Perl can only do that via function call or eval, both of which have overhead that I hope we're not implying. GNU C solves this problem in C by introducing the extension, "({})" like so: #define swapout(a,b,new) ({typeof(a) tmp=a;a=b;b=new;tmp;}) old1 = swapout(var1,var2,rand(100)); Which, behaves suspiciously like Perl and (which got this behavior from LISP) ;) The value of the last statement in the block would be the return value of the EXPRESSION (it's not a statement). So, this concept (if not the syntax) would help us in Perl, because the above statement would macro-expand to: @x = ({ my @list = ({$fh.getlines()}); my @newlist; for @list { push @newlist, $_ if ({/\S/}); } return @newlist; }); This is not a great example because /\S/ is a valid expression, but if we called it with something more complex, you would need this to expand the macro. Perl will never have to do this, as it'll all be syntax tree internally, but it would be nice to be able to expand byte code back out to Perl without introducing extra overhead. In this sense, I see Perl's ({}) as being exactly the same as eval{} (or whatever the Perl6 version is), but without the exception trapping. The only problem is that in Perl, ({}) is already valid syntax (paren grouping around an anonymous hash). So, you might need to special case it, or come up with a different syntax (expr{} perhaps). > Just out of curiosity, is there anything macros (in the Lisp sense) > can do that source filters can't? By definition, no. However, it would be harder for your source filter to deal with the language correctly. It's difficult in C. In Perl it might be impossible to get it right a majority of the time.
Re: Perl6 Macros
> > An example of where variable capture is needed is: > > macro println ($a) { > > return <<"EOF"; > > print $a; > > print "\n"; > > EOF > > } > > for my $b (1..100) { > > println $b; > > } > > And, if we inline the sub, the only difference will be...? Okay, a bad example, in that it could be better done in other ways. Basically, the println macro is receiving $a='$b', not $a=$b. So when it plugs $a into the returning string, its actually plugging $b, which needs to get interpolated into the callers lexical scope. > macro mygrep ($code is macroblock, *@list) { > my @newlist = (); > for @list { > push @newlist, $_ if $code.(); > } > return @newlist; > } > @x = mygrep {/\S/} $fh.getlines(); > > where no code reference is ever created. It could be abused mercilessly, > but I can see the massive savings in performance that we would reap, > especially when translating/compiling this code for native or JIT > execution. This is because we don't have to fire a function call each > time we execute the block. In this example, you're using macros for compile-time computation. There's two interpretations in the manner you given. If *@list is the list of arguments being passed to mygrep, then @list contains ('$fh.getlines()'), and this isn't doing what you want. An alternative approach might be to define it as: macro mygrep ($code is macroblock, *$list) { my $return = <<'EOF'; my @newlist = (); EOF $return .= "for ($list) {\n"; $return .= <<'EOF'; push @newlist, $_ if $code.(); } return @newlist; EOF return $return; } @x = mygrep {/\S/} $fh.getlines(); Admittedly confusing due to the combination of perl code, and perl code returning perl code. This was the whole reason for the backtick and comma operators in scheme. The above macro would take the rest of the arguments to mygrep as a string, and plug them into the 'for', so that the result would have "for ($fh.getlines())" instead of "for ('$fh.getlines()')". A better use of macros for this compiletime computation might be something like: macro mapstatic ($code, *@list) { return make_perl_list( map $code @list); } print mapstatic {$_.$_} "A".."Z"; which would print: AABBCCDDEEFF, etc Yes, this can easily be done with a regular map, but the regular map would be performed everytime the code is run, which could be bad for performance inside a tight loop. I'm still fleshing out my ideas for making macros with a perlish syntax, which I'll post in a seperate email. Mike Lambert
Re: Perl6 Macros
New syntax is 'qs', aka quote sub, which is similar to q, except that it interpolates all of: ${..} @{..} and %{..} All subroutines which are interpolated, are interpolated as regular text, with no bindings, so that they get lexically scoped in the code they are returned as part of. Then macros essentially return a string which gets interpolated at the call site. macro while ($cond, $body) { return qs{ GENLABEL: goto ENDLABEL if( ${ $cond } ); ${ $body }; goto GENLABEL; ENDLABEL: } } $a = 10; while {$a>0} { $a--; print $a; } Or maybe, if 'macro while' is defined as: macro while ($cond as paren-sub, $body) { while( $a> 0 ) { } macro for qw( '(', $var, $low, $high, ')', $body ) { return qs{ my ${ $var } = $low; my $end = ${ high }; GENLABEL: goto ENDLABEL if (${ $var } > $end); ${ $body }; ${ $var }++; goto GENLABEL; ENDLABEL; } } for ($i 1 10) { } or alternately, if 'macro for' is defined as: macro for ( $var, '=', $low, 'to', $high, $body ) { for $i = 1 to 10 { } The syntax isn't as powerful as scheme's despite the above extensions to the parameter list, because scheme has such a 'simple' syntax, so there is no real confusion about argument parameters. Another possible parameter syntax is something that's along the lines of a grammar, so it can have a better idea about where to start, stop, and handle errrors, for parsing calls to macros. The ugliness of the symbols is necessary for the more lowlevel macros that would compile down to very simple ops, and thus make translation to the parrot bytecode that much easier. One additional thing the above need is that either GENLABEL and ENDLABEL need to be renamed by qs() so that while's within while's don't have problems, or we'd need to follow Scheme's example of gensym, which constructs unique symbols. In theory, it might be possible to define the language in terms of macros. Then you just write a macro parser, and you've got your (probably slow as hell to compile) language. ;) Anyways, I'm trying to move beyond the stage of getting others excited about macros, and trying to propose syntax, so they aren't just wishful thinking. I understand the above syntax probably does have ambiguities which aren't easily resolved, but I'm trying to get the ball rolling. I'm just hoping Larry has some wonderful macro syntax up his sleeve, waiting to wow us all with. :) Mike Lambert
Re: Perl6 Macros
First impression: Don't go there. Longer answer: On Wed, 2002-03-27 at 16:29, Michel J Lambert wrote: > New syntax is 'qs', aka quote sub, which is similar to q, except that it > interpolates all of: ${..} @{..} and %{..} > All subroutines which are interpolated, are interpolated as regular text, > with no bindings, so that they get lexically scoped in the code they are > returned as part of. > Then macros essentially return a string which gets interpolated at the > call site. > > macro while ($cond, $body) { > return qs{ > GENLABEL: > goto ENDLABEL if( ${ $cond } ); > ${ $body }; > goto GENLABEL; > ENDLABEL: > } > } Ok, ignoring the fact ${ $body } seems to be wildly non-intuitive syntax for a single-interpolation, I don't see the value of manipulating macros as string at all. We have eval for that (eval+anon subs+closures is 99% of what LISP macros are, and I think that's what you're modeling this after). Macros could add something to Perl, but I don't see why having a macro return a string instead of looking and acting like a subroutine would be a bad thing. In fact, as I pointed out before, you can do almost all of the scoping stuff that you would want out of a macro in Perl with the existing subroutine/code ref syntax and a special property. Again, that would look like (a third syntax actually, but very similar to what I suggested before): sub uvula($cond,$body) is macro { while($cond.()) { $body.(); } } uvula cond => sub{$_ = $fh.getlines() }, body => sub{ print; }; There may be some simpler way to construct the call (this should all be standard Perl6 syntax, I'm not trying to change anything here), but this overly verbose invocation avoids my having to demonstrate that I'm not sure how such things are being handled in Perl6 yet. You just "explode" the code ref so that it does not construct its own scope (actually, it does, in the same way that braces do, but not to the extent that subroutines do... I'd have to look at the source to remember the difference there). > The ugliness of the symbols is necessary for the more lowlevel macros that > would compile down to very simple ops, and thus make translation to the > parrot bytecode that much easier. One additional thing the above need is > that either GENLABEL and ENDLABEL need to be renamed by qs() so that > while's within while's don't have problems, or we'd need to follow > Scheme's example of gensym, which constructs unique symbols. If labels are lexically scoped, There's no problem here. Of course, you need to "promote" all lables to the beginning of the enclosing block, but that's compiler magic, and doesn't violate lexical scoping.
Re: Perl6 Macros
Basically, one of the goals of Perl6 was to allow for you to implement any perl construct, in perl. None of the operators were to use any special features that could not be done by regular subroutines. And personally, I don't see how we're going to be able to do all this lazy evaluation of parameters (and, if/else, etc), different lexical scopes for passed coderefs (foreach), and so on. Lisp macros provide the ability to implement the semantics of every single one of these constructs, but unfortunately, has the horribly monotonous syntax. And so my goal is to provide those same semantics to Perl, with the wonderfully appropriate and concise syntax. I'm not sure whether such a goal is achievable, however. > Ok, ignoring the fact ${ $body } seems to be wildly non-intuitive syntax > for a single-interpolation, I don't see the value of manipulating macros > as string at all. We have eval for that (eval+anon subs+closures is 99% > of what LISP macros are, and I think that's what you're modeling this > after). Fine, I agree that manipulating macros as strings isn't a great idea. But it's the closest way to perform the perl equivalent to the lisp original. > Macros could add something to Perl, but I don't see why having a macro > return a string instead of looking and acting like a subroutine would be > a bad thing. In fact, as I pointed out before, you can do almost all of > the scoping stuff that you would want out of a macro in Perl with the > existing subroutine/code ref syntax and a special property. I disagree here. How would I define foreach as a macro (assuming the following, simplified syntax). foreach $each, @array, { print $each; }; Since $each is being passed to the foreach macro, the macro needs to create a lexical scoping for $each, and place the third argument as a loop body, within the context of the scoping it just defined. One could argue that you could do: foreach my $each, ... And that parameters passing variables with 'my' prefixed get lexically scoped at the caller, and so the subroutine would be within it. But that's not really consistent, and is actually confusing. It also begs the question, how does $_ get scoped? > sub uvula($cond,$body) is macro { > while($cond.()) { > $body.(); > } > } > uvula cond => sub{$_ = $fh.getlines() }, body => sub{ print; }; Ugliness aside, it's only advantage is that it could inline the contents of the macro sub, and that could be better done with simple inlined functions, and don't require the complexity of macros. Macros are better suited to things that *cannot* be done with functions. Stealing from "On Lisp", macros have the following advantages (pages 107-109 to be precise): - Transformation: they can look inside the structure of their arguments. pow($a,$b) can be optimized if the second argument is constant. This can be done with a macro which checks whether the second parameter to it is an expression, or a constant, and perform the appropriate logic. - Binding: I've already explained this one to death. "Any operator which is to alter the lexical bindings of its arguments must be written as a macro." - Conditional evaluation: how would you write 'if' or 'and' using functions? - Multiple evaluation: this can be emulated by receiving coderefs, and calling them multiple times. But it requires the caller format them *as* a coderef. - Using the calling environment: I believe Damian likes this one for Exporter, and flexibility, and Dan doesn't for optimization reasons. Macros give the BOBW. - Saving function calls: A minor one, which can be emulated with inlined functions > If labels are lexically scoped, There's no problem here. Of course, you > need to "promote" all labels to the beginning of the enclosing block, > but that's compiler magic, and doesn't violate lexical scoping. If they're lexically scoped, yes. But this doesn't solve all the problems. For example, what if, in this macro, I pass the 'jumpto' label to another macro I'm calling. There's no guarantee that the inner macro, when it uses the label I passed it, will work, since it could accidentally re-scope the macro name itself for its own purposes. Thus, the problems with variable capture, and the reasons for gensym. Since macros are using a function-similar syntax, and functions are necessarily prefix-based, it means macros are unable to express curtain Perl constructs. For example 'A if B' type syntax is difficult to implement with macros, which requires the macro name be seen before it can process the code as a macro. Unless macros get further perlized in some manner in some way. I feel like this is a two-person debate, and the volume of text is going to alienate other contributors. So I'll shut up on this topic, and wait to see what Larry/Damian thinks of the 'good'ness of the idea before I try and flesh out more ideas on the implementation. Mike Lambert
Re: Perl6 Macros
Michel J Lambert <[EMAIL PROTECTED]> writes: > > > Macros could add something to Perl, but I don't see why having a macro > > return a string instead of looking and acting like a subroutine would be > > a bad thing. In fact, as I pointed out before, you can do almost all of > > the scoping stuff that you would want out of a macro in Perl with the > > existing subroutine/code ref syntax and a special property. > > I disagree here. How would I define foreach as a macro (assuming the > following, simplified syntax). > foreach $each, @array, { > print $each; > }; > > Since $each is being passed to the foreach macro, the macro needs to > create a lexical scoping for $each, and place the third argument as a loop > body, within the context of the scoping it just defined. That suggested a similar example to me... In Lisp (or, more likely, Scheme), you get constructs like: (let ((a 'b) (c 'd) ... ) (...)) being defined as equivalent to: ((lambda (a c ...) (...)) 'b 'd ...) and the macro system can convert the let into the evaluated lambda. Suppose we wanted to have a Perl construct that was similar: my $a = let ($b -> 5, $c -> $x) { $b + $c }; The most similar replacement for the let to the lisp case is: my $a = &(sub { my ($b, $c) = @_; return $b, $c; })(5, $x); With the macro system (using qs() for things to be evaluated at compile time), I could see something like: macro let (%&) { &(sub { my qs(keys @_[0]) = @_; return qs(@_[1]); })(qs(values @_[1]))}; I'm not sure that that would work perfectly offhand (I suspect some syntax tweaking would be necessary) but it's the basic idea I think you are going for. -- Buddha Buck [EMAIL PROTECTED] "I will not die an ironic death" -- Scott Ian, lead singer for the metal band Anthrax, after bioterrorist attacks using anthrax.