perlquestion LanX Hi<P><P> <H4> Introduction<P></H4><P> I'm doing a case study to simulate [|Perl6 -Meta-Operators] in Perl5 and I'm stuck with a special when restricting myself to pure FP. <P><P> See for instance [|the Cross operator X]<P><P> <c> <a b> X 1,2 X <x y> #produces ('a', 1, 'x'), ('a', 1, 'y'), ('a', 2, 'x'), ('a', 2, 'y'), ('b', 1, 'x'), ('b', 1, 'y'), ('b', 2, 'x'), ('b', 2, 'y') </c><P><P> can be simulated with<P><P> <c> pp X {"a".."d"}; pp X {"a".."b"} X {1..2} X {'x','y'}; my $iter = X {"a","b"} X {1..2} X {'x','y'}; while ( my ($aref)= $iter->() ) { pp $aref; } __DATA__ (["a"], ["b"], ["c"], ["d"]) ( ["a", 1, "x"], ["a", 1, "y"], ["a", 2, "x"], ["a", 2, "y"], ["b", 1, "x"], ["b", 1, "y"], ["b", 2, "x"], ["b", 2, "y"], ) ["a", 1, "x"] ["a", 1, "y"] ["a", 2, "x"] ["a", 2, "y"] ["b", 1, "x"] ["b", 1, "y"] ["b", 2, "x"] ["b", 2, "y"] </c><P><P> Where <C>X</C> is a function with signature (&;$) which accepts an iterator as second argument and returns an iterator.<P><P> So in LIST context it produces the whole array in scalar context it just returns a lazy iterator. (i.e. allowing infinite lists)<P><P> This functions (and similar others) can be nested and produce nice syntactic sugar, for instance the above has the following precedence<P><P> <c> X {"a","b"} ( X {1..2} ( X {"x","y"} ) )</c><P><P> Here my purely functional implementation so far. <P><P> (Please note that this is a <b>case study for the API</b> and not optimized for speed. A well designed and tested set of such operators could be optimized and/or reimplemented in XS later, w/o messing with the P5's parser while being as closs as possible to P6 semantics.)<P><P> <readmore> <c> use strict; use warnings; use feature qw/say/; use Data::Dump qw/pp/; sub gen_listiter { my @init=@_; my @list=@init; sub { if (@list) { return shift @list } else { @list=@init; return () } } } sub get_array { my $iter=shift; my @res; while ( my ($res)= $iter->() ) { push @res,$res; } return @res; } my %operations =( '+' => sub { defined $_[1] ? $_[0] + $_[1]->[0] : $_[0] }, ); sub X (&;$) { my ($cr,$tail_itr)=@_; # my $op = $operations{$tail_itr} if defined $tail_itr; # undef $tail_itr if $op; $tail_itr //= gen_listiter([]); my $head_itr = gen_listiter($cr->()); my $state='INIT'; my $head; my $tail; my $op //= sub { [ $_[0],@{$_[1]} ] }; my $cross_itr = sub { goto $state; INIT: $state="RESUME"; while ( ($head) = $head_itr->() ) { while ( ($tail) = $tail_itr->() ) { return $op->($head,$tail); RESUME: } } $state='INIT'; return; }; if (wantarray) { return get_array($cross_itr); } else { return $cross_itr; } } pp X {"a".."d"}; pp X {"a".."b"} X {1..2} X {'x','y'}; my $iter = X {"a","b"} X {1..2} X {'x','y'}; while ( my ($aref)= $iter->() ) { pp $aref; } </c> </readmore><P><P> <H4> Extension<P></H4><P> Perl6 also allows to use sub-operators which are applied to each combination, like:<P><P> <c> my @a = 1, 2; my @b = 3, 4; my @c = @a X+ @b; # 1+3, 1+4, 2+3, 2+4 </c><P><P> this could be simulated by passing a string or a anonymous sub in the last parameter slot.<P><P> <c> my @a = 1, 2; my @b = 3, 4; my @c = X{@a} X{@b} '+' </c><P><P> An operator symbol like '+' would just be looked up and produce something like 'sub {$a+$b}' to be applied.<P><P> <H4> Problem<P></H4><P> Only the rightmost X has the information about the operation and there is only one slot free to pass an iterator.<P><P> Is it possible to write the intermediate (and final) iterators in a <b>purely functional</b> way that the operation (here plus) is incapsulated within the logic of the passed iterators?<P><P> Of course there are ways to cheat with OOP by blessing/tying the iterator-ref and returning the operation with something like <c>$op = $iter->get_op()</c><P><P> Another (ugly) way is to check the passed parameters within the iterator <c> $op = $iter->("get_op") </c><P><P> One functional solution could be that all nested iterators just call the next one and append the values so far, and the lowest nested iterator encapsulates the operation and adds over all values <c> reduce {$a+$b} @_ </c> and returns the result thru all levels.<P><P> This approach is less optimal, since it inhibits any benefit from memoization, cause <c>sum($a,$b,$c) = sum($a, sum($b,$c))</c>, so many intermediate results from subtrees could be cached. Memoization would result in an extreme performance boost.<P><P> I hope my intention is clear now, I don't know there is a solution but it helped talking about it. =)<P><P> So there are work arounds but I wonder if a purely functional approach with just one passed function is possible...<P><P> <!-- Node text goes above. Div tags should contain sig only --> <div class="pmsig"><div class="pmsig-708738"> <p>Cheers Rolf <p> <small>( addicted to the Perl Programming Language) </small> </div></div><P><P> <H5> update<P></H5><P> PS: If you are wondering about the title ... I was in a hurry and my brain entered a German word so <c>s/mit/with/</c>. :)