# PODNAME: Seq
# ABSTRACT: What is Seq, and how do I use it?

__END__

=head1 NAME

Seq - A lazy sequence implementation

=head1 SYNOPSIS

A sequence is a builder/generator for iterators. You use a sequence and describe
operations on a sequence. A sequence can then be asked to return an iterator
that do the actual work.

The idea is that you never use the iterators directly. You only use a sequence.
The iterator behind it is an implementation detail.

The advantage is that you have a high-level API with map, filter, fold and so
on. It combines all the functionality you see from map, grep, List::Util, ...

But it does it lazily instead of computing everything at once. Thus it can
provide immidiat results (when possible), use less memory. Sometimes even
saving computation time.

Once you have defined a sequence. You can execute the sequence as often you
want on whatever data you give it.

You never use the iterators directly. As a sequence generates iterators when
needed, you always can execute a sequence as often as you want. From its usage
it looks like an immutable iterator.

    # always represents the range from 1 to 100.
    my $range = Seq->range(1,100);

    # prints numbers 1 to 100
    $range->iter(sub($x) { say $x });

    # prints numbers 1 to 100 again ...
    $range->iter(sub($x) { say $x });

At the moment Documentation is lacking, but the source-code is well-documented
including the test-files. Maybe you want to look at the test-files until
I have written more documentation. The API is not fully stable at the moment.

    use v5.36;
    use Seq;

    # Fibonacci Generator
    my $fib =
        Seq->concat(
            Seq->wrap(1,1),
            Seq->unfold([1,1], sub($state) {
                my $next = $state->[0] + $state->[1];
                return $next, [$state->[1],$next];
            })
        );

    # prints: 1 1 2 3 5 8 13 21 34 55 89 144 233 377 610 987 1597 2584 4181 6765
    $fib->take(20)->iter(sub($x) {
        say $x;
    });

    # Represents all possible combinations
    # [[clubs => 7], [clubs => 8], [clubs => 9], ...]
    my $cards =
        Seq::cartesian(
            Seq->wrap(qw/clubs spades hearts diamond/),
            Seq->wrap(qw/7 8 9 10 B D K A/)
        );

    use Path::Tiny qw(path);
    # get the maximum id from test-files so far
    my $maximum_id =
        Seq
        ->wrap(   path('t')->children )
        ->map(    sub($x) { $x->basename })
        ->choose( sub($x) { $x =~ m/\A(\d+) .* \.t\z/xms ? $1 : undef } )
        ->max;

=head1 CONCEPT

Describe CONSTRUCTORS, METHODS (Find another name), CONVERTERS.

=head1 EXPORT

This modules does not export anything by default. But you can request the
following functions.

=head2 id

return its input as-is

    sub id($x) { return $x }

=head2 fst

return the first element of an array

    sub fst($array) { return $array->[0] }

=head2 snd

return the second element of an array

    sub snd($array) { return $array->[1] }

=head2 key

generates a function that picks a value from a hash.

    sub key($name) { sub($hash) { return $hash->{$name} } }

=head2 assign

allows you to assign a value, but also do a computation.

    my $value = assign {
        my $x = ...  # code to compute $x
        my $y = ...  # code to compute $y
        $x + $y;
    };

Same as

    my $value;
    {
        my $x = ...  # code to compute $x
        my $y = ...  # code to compute $y
        $value = $x + $y;
    }

=head1 CALLING STYLE

Describe functional and chaining style here.

=head1 CONSTRUCTORS

This module uses functional-programming as the main paradigm. Functions are
divided into constructors, methods and converters.

Constructor create a sequence. Methods operate on sequences and return
another new sequence. Converter transforms a sequence to some other data-type.

Methods are called methods for convenience, but no object-orientation is
involved. Perls OO capabilities are only used as a chaning mechanism.

Constructors must be called with the Package name. Functions that operate
on Sequences can either be called as a method or directly from the Package.

    my $range =
        Seq
        ->wrap(1,2,3)
        ->append(Seq->wrap(4,5,6));

or

    my $range =
        Seq::append(
            Seq->wrap(1,2,3),
            Seq->wrap(4,5,6),
        )

=head2 $seq = Seq->empty()

Returns an empty sequence. Useful as an initial state or as a starting point.

    Seq->empty->append( $another_seq )

=head2 $seq = Seq->range($start, $stop)

Returns a sequence from $start to $stop. Range can also be backwards. $start
and $stop are inclusive.

    Seq->range(1, 5); # 1,2,3,4,5
    Seq->range(5, 1); # 5,4,3,2,1
    Seq->range(1, 1); # 1

=head2 $seq = Seq->wrap(...)

Just takes whatever you pass it to, and puts it in a sequence. This should be
your primarily way to create a sequence with values.

    Seq->wrap(qw/Hello World/); # "Hello", "World"
    Seq->wrap(1 .. 10);         # AVOID this, use Seq->range(1, 10) instead.
    Seq->wrap(@array);

=head2 $seq = Seq->concat(@sequences)

Takes multiple *Sequences* and returns a single flattened sequence.

    # 1, 2, 3, 4, 5, 5, 4, 3, 2, 1
    Seq->concat(
        Seq->range(1, 5),
        Seq->range(5, 1),
    );

=head2 MISSING DOC

Implemented, but not documented yet:

from_sub, unfold, init, range_step, from_list, from_array, from_hash

=head1 METHODS

Implemented, but not documented yet:

append, map, bind, flatten cartesian, join, merge, select*, choose, mapi,
filter, take, skip, indexed, distinct, distinct_by, iter, do, rev

* will maybe change

=head1 CONVERTERS

Implemented, but not documented yet:

fold, reduce, first, last, to_array, to_list, count, sum, sum_by, min,
min_by, min_by_str, max, max_str, max_by, max_by_str, str_join, to_hash,
group_by, find


=head1 Github

Development project is on Github. L<https://github.com/DavidRaab/Seq>

=head1 AUTHOR

David Raab, C<< <davidraab83 at gmail.com> >>

=head1 LICENSE AND COPYRIGHT

This software is Copyright (c) 2023 by David Raab.

This is free software, licensed under:

  The MIT (X11) License
