Austin Hastings writes: > Suppose I want to say: > > sub sublist(@a, $start, $cnt) { > return @a[$start] +next --$cnt; > } > > where +next is a binary macro that takes as its lhs an array element > access, and its rhs a number, and returns a list of the array element > followed by the next RHS elements.
First, I don't believe you can do that, as the macro name comes after one of the things it needs to specially parse. So first, let's turn it into: sub sublist(@a, $start, $cnt) { return with_next(@a[$start], $cnt-1) } (You can't modify $cnt unless it's declared C<rw> or C<copy>. Does -1 achieve the same semantic effect you were looking for?) > It seems obvious to me that +next has to be a macro, since it has to > detect this weird condition of "accessing an array element". How do I > code that? True, it does. You could do that with a custom parse (requiring a copy of the Perl 6 grammar in order to know where to hook in). But, judging from below, I think you're getting at something else. > More generally, is there any way (via trait or property or whatever) > to recognize when something as basic as $_ is an array element, and > get the containing array(s) and somehow do the right thing? > > (I can't count the number of times I've been frustrated by map/grep > because there's no way to get at the "next" or "prior" element in the > sequence.) I, too, have been frustrated by this a couple times. More commonly it's when I'm C<foreach>ing over an array, and I have to switch to a C-style for because I need to get the next element. It's not possible to recognize when something like $_ is an array element, as it might be an element of more than one array. The best solution I can see right now is to make the parameter(s) to for, map, grep, etc. an iterator instead of just the value. In fact, I talked about this in a thread entitled "The Object Sigil" awhile back. The idea was to make $_ delegate in all cases, and have a specific operator that marks when I<not> to delegate. This is because it feels wrong to me to delegate in most cases except for certain methods. Like junctions do. Ick. But we've already been through that, so I won't bring it up again. You might have: for @foo { print if .next < $_; } To print the local maxima of a sequence. The problem comes up when the objects you're iterating over also have a C<next> method. I think of something like a C<real> method, that lets you access the original, non-iterator object: for @foo { print .real.next; # $_'s next, not the iterator's next print .real.real.next; # It's possible that @foo contains iterators } That seems like a pretty good solution. The only problem is that the user of the iterator needs to know all the methods that an iterator has in order to stay out of trouble. Makes it pretty hard to add methods without breaking things. Turning that upside-down we get a slightly uglier, but maintainably much nicer solution. for @foo { print .next; # $_'s next, not the iterator's print .iter.next; # The iterator's next } In fact, this is precisely what "The Object Sigil" was proposing, except it used punctuation instead of a method. Either way works. Then you get the slightly esoteric case when $_ has a 'iter' method itself. That should happen so infrequently that this should suffice: for @foo { print .iter.real.iter; } Bringing it back home, it's possible that an array access C<@foo[$ind]> would return a similar iterator, making the answer to your question obvious. However, at first glance, that seems like a bad idea. I'm a little too tired to explore it more fully at the moment. Luke