# PODNAME: Seq::Manual::FromSub
# ABSTRACT: Explanation of Seq->from_sub()

__END__

=head1 Seq::Manual::FromSub

A deeper explanation how Seq->from_sub() works.

=head1 THE PROBLEM

You could write the following in Perl

    Seq->wrap(1 .. 10_000_000)

but it would be a bad idea. Perls range operator is non-lazy. When
you call the above code. Perl will create an array with 10 Mio numbers
and then pass that 10 Mio numbers to wrap().

This is not only time-consuming, it will also use a lot of memory. Maybe
with a biger number your program or your computer could even crash
with out of memory.

This is the reason why you should use

    Seq->range(1, 10_000_000)

instead. It returns a sequence but nothing is computed yet. It only starts
computing values when the sequence is request for values. And even then it will
still only compute as much as needed, or keep those values in memory
that are needed.

Seq->range() is already provided by this module. But what would be the case
if not?

Then you could create your own range function using Seq->from_sub()

=head1 range

Here is how to implement your own range() function.

    sub range($start, $stop) {
        ###-- -- -- -- -- IMPORTANT -- -- -- -- --###
        #          NO CODE SHOULD BE HERE           #
        #    Otherwise it will be CAUSE of BUGS.    #
        # You also should never manipulate function #
        # arguments not even assign a new value to  #
        # it. Do an explicit new assignment in the  #
        #          INITIALIZATION STAGE             #
        ###-- -- -- -- -- -- --- -- -- -- -- -- --###
        return Seq->from_sub(sub {
            # INITIALIZATION STAGE:
            my $current = $start;

            # The iterator returning one element when asked
            return sub {
                # As long $current is equal or smaller
                if ( $current <= $stop ) {
                    # return $current and increase by 1
                    return $current++;
                }
                # otherwise return undef to indicate end of sequence
                else {
                    return undef;
                }
            }
        });
    }

The pattern you do with from_sub() is always the same. It is.

    my $sequence = Seq->from_sub(sub {
        # INITIALIZATION CODE HERE

        return sub {
            # RETURN ONE ELEMENT OR UNDEF TO ABORT SEQUENCE
        };
    });

You can use it directly to create a special sequence as needed, or return
it from a function. So you have a reusable CONSTRUCTOR for creating your
own sequences.

Maybe the most simple sequence would be an infinity sequence always returning
the same value forever.

    my $always = Seq->from_sub(sub {
        return sub {
            return 1;
        }
    });

You could do

    $always->take(10)->to_array

to just get an array [1,1,1,1,1,1,1,1,1,1]. Don't forget the take(10)
otherwise the sequence will run forever until all your computer memory
is exhausted and your program or computer crashes.
