Data-Enumerable-Lazy

 view release on metacpan or  search on metacpan

README  view on Meta::CPAN

NAME
    Data::Enumerable::Lazy - Lazy generator + enumerable for Perl5.

SYNOPSIS
    A basic lazy range implementation picking even numbers only:

      my ($from, $to) = (0, 10);
      my $current = $from;
      my $tream = Data::Enumerable::Lazy->new({
        on_has_next => sub { $current <= $to          },
        on_next     => sub { shift->yield($current++) },
      })->grep(sub{ shift % 2 == 0 });
      $tream->to_list(); # generates: [0, 2, 4, 6, 8, 10]

  DESCRIPTION
    This library is another one implementation of a lazy generator +
    enumerable for Perl5. It might be handy if the elements of the
    collection are resolved on the flight and the iteration itself should be
    hidden from the end users.

    The enumerables are single-pass composable calculation units. What it
    means: An enumerable is stateful, once it reached the end of the
    sequence, it will not rewind to the beginning unless explicitly forced
    to. Enumerables are composable: one enumerable might be an extension of
    another by applying some additional logic. Enumerables resolve steps on
    demand, one by one. A single step might return another enumerable (micro
    batches). The library flattens these enumerables, so for the end user
    this looks like a single continuous sequence of elements.

      [enumerable.has_next] -> [_buffer.has_next] -> yes -> return true
                                                  -> no -> result = [enumerable.on_has_next] -> return result

      [enumerable.next] -> [_buffer.has_next] -> yes -> return [_buffer.next]
                                              -> no -> result = [enumerable.next] -> [enumerable.set_buffer(result)] -> return result

EXAMPLES
  A basic range
    This example implements a range generator from $from until $to. In order
    to generate this range we define 2 callbacks: `on_has_next()' and
    `on_next()'. The first one is used as point of truth whether the
    sequence has any more non-iterated elements, and the 2nd one is here to
    return the next element in the sequence and the one that changes the
    state of the internal sequence iterator.

      sub basic_range {
        my ($from, $to) = @_;
        $from <= $to or die '$from should be less or equal $to';
        my $current = $from;
        Data::Enumerable::Lazy->new({
          on_has_next => sub {
            return $current <= $to;
          },
          on_next => sub {
            my ($self) = @_;
            return $self->yield($current++);
          },
        });
      }

    on_has_next() makes sure the current value does not exceed $to value,
    and on_next() yields the next value of the sequence. Note the yield
    method. An enumerable developer is expected to use this method in order
    to return the next step value. This method does some internal
    bookkeeping and smart caching.

    Usage:

      # We initialize a new range generator from 0 to 10 including.
      my $range = basic_range(0, 10);
      # We check if the sequence has elements in it's tail.
      while ($range->has_next) {
        # In this very line the state of $range is being changed
        say $range->next;
      }

      is $range->has_next, 0, '$range has been iterated completely'
      is $range->next, undef, 'A fully iterated sequence returns undef on next()'

  Prime numbers
    Prime numbers is an infinite sequence of natural numbers. This example
    implements a very naive suboptimal prime number generator.

      my $prime_num_stream = Data::Enumerable::Lazy->new({
        # This is an infinite sequence
        on_has_next => sub { 1 },
        on_next => sub {
          my $self = shift;
          # We save the result of the previous step
          my $next = $self->{_prev_} // 1;
          LOOKUP: while (1) {
            $next++;
            # Check all numbers from 2 to sqrt(N)
            foreach (2..floor(sqrt($next))) {
              ($next % $_ == 0) and next LOOKUP;
            }
            last LOOKUP;
          }
          # Save the result in order to use it in the next step
          $self->{_prev_} = $next;



( run in 0.635 second using v1.01-cache-2.11-cpan-39bf76dae61 )