in reply to Re: An iterator for (not "iterating") a recursive data structure.
in thread An iterator for (not "iterating") a recursive data structure.

Some remarks/meditations:

Solving the initial problem

Should be noted that the initial problem of the OP (short-circuiting a call-back) is easily solved with goto

cbIterator { goto STOP if $_ >700; print; } \@nested; STOP:

#! perl -slw use strict; use Data::Dump qw[ pp ]; sub genNested { my $n = shift; map{ rand() < 0.5 ? [ rand(1000), genNested( $n-1 ) ] : rand( 1000 + ) } 1 .. $n; } sub cbIterator (&$) { my( $code, $tree ) = @_; for my $i ( 0 .. $#$tree ) { if( ref( $tree->[ $i ] ) eq 'ARRAY' ) { &cbIterator( $code, $tree->[ $i ] ); } else { local $_ = $tree->[ $i ]; $code->(); } } } my @nested = genNested( 3 ); pp \@nested; my $count=0; cbIterator { goto STOP if $_ >700; $count++; print; } \@nested; STOP: print "stopped after $count iterations"; __END__ [ 477.675948149653, [ 127.346865922796, [497.437228434123, 201.338051626486], 374.088657613129, ], [ 767.071185158308, [597.589516628219, 84.8516920524318], [541.772816445729, 983.763599841957], ], ] 477.675948149653 127.346865922796 497.437228434123 201.338051626486 374.088657613129 stopped after 5 iterations

Terminology: What's an "Iterator"?

Than there is some terminology confusion, in my books ( IIRC including Higher Order Perl ) this "pass a call-back" approach isn't an iterator but something I'd maybe call a diver or walker ¹, which does the iteration inside out by processing a call-back.

I.o.W for me in Perl speak:

iterator := iterator function

I checked Iterator on WP and of course there is still confusion, but at least someone proposed Iteratee

Iteratee, in which, instead of the developer calling the iterator repeatedly to get new values, the iteratee is called repeatedly to process new chunks of data - an example of inversion of control

Where your solution excels

The real problem with iterators in Perl is how to continue them after the first stop. (The OP didn't ask this)

Thats why Perl6 introduces gather/take and Python has "generators" with yield constructs.

Since you're flattening the recursion into a loop with its own call @stack , this can easily be used for such a "coroutine".

The trick is to store persisting data like @stack in the surrounding closure of the generator!

Finally

Hope this was of interest. :)

Cheers Rolf

PS: Je suis Charlie!

¹) I'd love to be pointed to some sources clarifying the terminology.

Replies are listed 'Best First'.
Re^3: An iterator for (not "iterating") a recursive data structure.
by BrowserUk (Patriarch) on Feb 13, 2015 at 15:29 UTC
    Should be noted that the initial problem of the OP (short-circuiting a call-back) is easily solved with goto

    Not if you wish to have the option of resuming the iteration; which I do. (Admittedly this was not mentioned in the OP.)

    In addition, this suffers from all the same problems as throwing an exception to effect the early exit, which is (ab)using the exception mechanism for flow control.

    Another reason for wanting an iterator is the ability to have multiple, concurrent, independent iterators; which is key to my application.

    Last but not least is the avoidance of the nightmare that is Inversion of Control.

    Think about how you'd have to restructure so many of your programs -- and how hard, if not impossible that would be -- if Perl's hashes only provided callback iterators. What a mess!


    With the rise and rise of 'Social' network sites: 'Computers are making people easier to use everyday'
    Examine what is said, not who speaks -- Silence betokens consent -- Love the truth but pardon error.
    "Science is about questioning the status quo. Questioning authority". I'm with torvalds on this
    In the absence of evidence, opinion is indistinguishable from prejudice. Agile (and TDD) debunked

      Amen! Nicely said.

      - tye        

      > Not if you wish to have the option of resuming the iteration;

      That's why I said

      > > Thats why Perl6 introduces gather/take and Python has "generators" with yield constructs.

      Cheers Rolf
      (addicted to the Perl Programming Language :)
      Wikisyntax for the Monastery FootballPerl is like chess, only without the dice

Re^3: An iterator for (not "iterating") a recursive data structure.
by MidLifeXis (Monsignor) on Feb 13, 2015 at 14:38 UTC

    If I were to have implemented this in code, I would have probably wrapped this into something like Iterator::Simple, which wraps the 'iteratee' into an object, and adds syntactic sugar that sets it up to be accessed with ->next(), <$it>, and other sugar and coercions that help to gloss over some of the details. I believe that the object created by the module would fit the definition of the iterator. I do agree that the function I provided should have probably been referred to in my test code as $cb or some such.

    --MidLifeXis

      > should have probably been referred to in my test code as $cb

      I wasn't criticizing you, the whole thread is fuzzy. :)

      edit

      Thx for pointing me to Iterator::Simple :)

      Cheers Rolf

      PS: Je suis Charlie!

        No personal criticism taken. I usually try to be clear in my examples, as in our field, precision in terminology is important. Your critique was, from a technical perspective, spot on. :-)

        --MidLifeXis