NAME

Seq - A lazy sequence implementation

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;

CONCEPT

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

EXPORT

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

id

return its input as-is

sub id($x) { return $x }

fst

return the first element of an array

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

snd

return the second element of an array

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

key

generates a function that picks a value from a hash.

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

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;
}

CALLING STYLE

Describe functional and chaining style here.

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),
    )

$seq = Seq->empty()

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

Seq->empty->append( $another_seq )

$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

$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);

$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),
);

MISSING DOC

Implemented, but not documented yet:

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

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

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

Github

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

AUTHOR

David Raab, <davidraab83 at gmail.com>

LICENSE AND COPYRIGHT

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

This is free software, licensed under:

The MIT (X11) License