1 2 3 4 5 6 7 8 9 10 11 12
sub Node::climb_up { my ($self, $sub, $cont) = @_; my $p = $self; my @ret; while ( $p = $p->parent_row ) { @ret = $sub->($p,\$cont); next if $cont; } return @ret; }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21
sub Node::climb_up { my ($self, undef, $sub) = @_; my $cont = \$_[1]; # Referenz auf urspr. Wert (Pass-by-Reference) my $p = $self; my @ret; while ( $p = $p->parent_row ) { @ret = $sub->($p); next if $$cont; } return @ret; } my $continue; my $curry_return = $node->climb_up($continue = 1, sub { my $node = shift; ... $continue = ...; return $in_spe; });
1 2 3 4 5 6 7 8 9 10 11 12
sub Node::climber { my $p = shift; return sub { return $p = $p->parent_row }; } # dann ... my $climber = $node->climber; while ( my $node = $climber->() ) { # ... }
2012-11-06T21:47:48 flowdyGibt es noch bessere Ideen? Ich suche nach einem guten Kompromiss zwischen Klarheit und Kürze im Aufrufkontext von &climb_up.
2012-11-06T21:47:48 flowdy[...]
Gibt es noch bessere Ideen? Ich suche nach einem guten Kompromiss zwischen Klarheit und Kürze im Aufrufkontext von &climb_up.
[...]
1 2 3 4 5 6 7 8 9 10 11 12 13
sub Node::climb_up { my ($self, $proc) = @_; my ($magic, @return); my $return_onTop = sub { @return = @_; die \$magic; }; COND_CLIMB: while ( $self = $self->parent_row ) { eval { @return = $proc->($self, $return_onTop) }; if ( $@ ) { $@ == \$magic ? next : die $@; } else { last COND_CLIMB; } } return @return; }
1 2 3 4 5 6 7 8 9 10 11 12 13
=head2 SYNOPSIS ... $node->climb_up(sub { my ($ancestor, $onTop_return) = @_; my $ret = $ancestor->doSomething(); return if $ret->smells(); # climb_up immediately returns () return do_whatever_with($ret); # i.e. any return values untouched $onTop_return->(@ignore_if_not); # Don't forget at the end! # otherwise ancestors' line processed ends by the parent # (blame perl it'd enforce an implied C<return @last_expr_val;> ) }
2012-11-08T12:49:53 flowdy[...]
Habe mir gedacht, dass das auch umgekehrt gehen müsste:
Code (perl): (dl )1 2 3 4 5 6 7 8 9 10 11 12 13sub Node::climb_up { my ($self, $proc) = @_; my ($magic, @return); my $return_onTop = sub { @return = @_; die \$magic; }; COND_CLIMB: while ( $self = $self->parent_row ) { eval { @return = $proc->($self, $return_onTop) }; if ( $@ ) { $@ == \$magic ? next : die $@; } else { last COND_CLIMB; } } return @return; }
[...]
Quote[...]
Ich glaube, my $closure = $node->climb_up(); have_fun($_) while $_ = $closure->() ist dann doch einen Deut besser. Ich kann es ja so machen, das climb_up() bei !@_ eine Closure zurückgibt, andernfalls eben so verfährt wie dargestellt.
EDIT: Das ist dann aber auch nicht kürzer als while ( $node = $node->parent_row ) {...}, ergo kann ich auf die Aufrufalternative ganz verzichten
[...]
QuoteAbgesehen davon ist die Exceptionbehandlung nicht unbedingt besonders schnell und könnte die Schleife ausbremsen, wenn sie in jedem Schritt durchlaufen wird.
1 2 3 4 5 6 7 8 9 10 11 12 13 14
sub Node::climb_up { my ($self, $proc) = @_; my ($i, $j, @return); my $return_onTop = sub { $j++; @_ }; while ( $self = $self->parent_row ) { @return = $proc->($self, $return_onTop); last if ++$i > $j; } continue { $j = $i; # falls $return_onTop mehrmals aufgerufen wurde } return @return; }
1 2 3 4
my @ret = $node->climb_up(sub { ... return [$val1, $val2, ...], $cont; })
2012-11-09T21:00:27 flowdyDass $curry_sub ja auch eine Liste von Werten zurückgeben könnte. Die müsste sie in einer anonymen Array-Referenz zurückgeben, die dann den ersten Rückgabewert bildet, damit der zweite Wert angeben kann, ob die Schleife fortgesetzt werden soll oder nicht.
[...]
return \@whatever, $exit_loop;
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28
sub climb_up { my $self=shift; # nur gerade Anzahl von Werten pop(@_) if(@_%2); my %options=@_; unless($options{code_find} and ref($options{code_find}) eq 'CODE') { croak(qq(in method "climb_up" "code_find" had to be defined! )); } $options{return_found}=1 unless(exists $options{return_found}); $options{break_on_undef}=1 unless(exists $options{break_on_undef}); my @ret; my $now=$self; while ( $now = $now->parent_row ) { my @r=$options{code_find}->($now); last if($options{break_on_undef} and @r==1 and !defined($r_[0])); push(@ret,@r) if($options{return_found}); } return 1 unless($options{return_found}); return @ret; }
1 2 3 4 5 6 7 8 9 10 11
$obj->climb_up(code_find=>sub{ my $obj=shift; if('was auch immer') { return qw(irgend ein array); } # kein Abbruch elsif('noch eine Auswahl') { return (); } # kein Abbruch elsif('noch eine Auswahl') { return undef,undef; } # kein Abbruch else { return undef; } # Abbruch });