So far only one use case, because (a) I haven't had time to write about the other ones, and (b) this was the one that came to mind quite strongly today.
There has been talk about this junction now and then; both on the #perl6
channel and in S09. Its semantics is pretty clear: put a list in a position where a scalar is expected, causing the statement to be executed for each of the list's elements.
%hash{each <foo bar baz>} = True; # assign each hash key
promote(each @employees); # call with each element as argument
@results.push(&filter(each @inputs)); # filter and push each input
each
feels like a good use case for a macro to me.
The interesting thing about each
from the viewpoint of a macro is that each
itself would mainly be saying "OK, turn the current statement into an 'each-y' statement". The main action would then have to happen after the entire statement was processed: wrapping the whole statement in a for
loop with a gensym'd loop variable, and replacing the each
with that loop variable.
The only question is how to inject that macro at the statement level. That we don't have a feature for, as far as I know. But I could see it being useful for all kinds of DSL-y things. I picture that feature as being akin to AOP's cutpoints, or Git's hooks: being able to inject logic into predefined points of the existing bits of compiler architecture.
Oh, and while we're talking about each
. I wonder what the semantics should be when there are several each
expressions in a statement. I can see several answers to that:
- It's disallowed. Two
each
es is complicated enough! Doesn't feel very Perl-y to put up such a limit, though. - Nested loops, in strict parse order, innermost loop first. Parse order is the way variable declaration/use works — you have to declare a variable on first use. So
say each(1, 2) + each(10, 20)
would output11 12 21 22
. The fact that I have to think hard here whether I like "innermost loop first" or "outermost loop first" doesn't speak well for the complexity of this alternative. - Nested loops, in evaluation order, innermost loops first. Would output the same for
say each(1, 2) + each(10, 20)
as the previous option, but would differ insay each(1, 2) + $_ given each (10, 20)
because thegiven
expression is evaluated before thesay
statement. Makes a certain amount of sense. The fact that I can't really decide between alternatives 2 and 3 also doesn't speak well for the complexity of these alternatives. - Run in parallel, just like
infix:<Z>
. Sosay each(1, 2) + each(10, 20)
would output11 22
.
Anyway. Did not paste this to discuss semantics — those bits came unbidden to me. But I do think each
fits nicely into what we should expect from Perl 6 macros if we want them to be useful and stand apart from subroutines.
So, helper functions for macros like each that:
-- Register some code to be run after the enclosing ast node (of type such-and-such) has been make'd.
-- Insert new ast before or after that existing ast node. (To be used by the code registered per 1).
?