Marc Chantreux > perlude-0.55 > lib/Perlude.pod

Download:
perlude-0.55.tar.gz

Annotate this POD

CPAN RT

New  2
Open  0
View/Report Bugs
Source   Latest Release: perlude-0.58

SYNOPSIS ^

A math example: every elements of fibo below 1000 (1 element a time in memory)

    use Perlude;
    use Modern::Perl;

    sub fibo {
        my @seed = @_;
        sub {
            push @seed, $seed[0] + $seed[1];
            shift @seed
        }
    }

    now {say} takeWhile { $_ < 1000 } fibo 1,1;

A sysop example: throw your shellscripts away

    use Perlude;
    use strictures;
    use 5.10.0;

    # iterator on a glob matches stolen from Perlude::Sh module
    sub ls {
        my $glob = glob shift;
        my $match;
        sub {
            return $match while $match = <$glob>;
            ();
        }
    }

    # show every txt files in /tmp
    now {say} ls "/tmp/*txt

    # remove empty files from tmp
    
    now { unlink if -f && ! -s } ls "/tmp/*"

    # something more reusable/readable ? 

    sub is_empty_file { -f && ! -s }
    sub empty_files_of { filter {is_empty_file} shift }
    sub rm { now {unlink} shift }

    rm empty_files_of ls "/tmp/*./txt";

BASICS and TERMS ^

Perlude is a brunch of functions (mainly stolen from the haskell Prelude) that ease programming with iterators by showing them as a stream (list of values that may be computed) instead of a sequence of calls. If you're used to a functionnal langage, the unix shell or the powershell: you're at home!

See a basic example (explanations and definition right after the code)

    sub seq { # the generator

        my $max = shift;
        my $x   = 1;

        sub { # the iterator construction

            # returning an empty list means that the stream is exhausted
            return if $x > $max;

            # else, return the next value of the stream
            # (undef is a valid value!)
            $x++;
        }
    }

    my $to5 = seq 5; # the iterator
    # remaining $to5 stream = 1, 2, 3, 4, 5

    say "first iteration: ", $to5->();
    # prints 1
    # remaining $to5 stream = 2, 3, 4, 5

    say join ', ', map $to5->(), 1..100;
    # call the remaining stream: exhaustion

    say to5->();
    # says nothing: $to5 is an exhausted stream

    # folding: store a stream in a array

    $to5 = seq 75;

    # fold 50 first values
    my @first = map $to5->(), 1..50;

    # fold 25 last  values
    my @last = map $to5->(), 1..50;

seq is a "generator": a function that returns an iterator.

$to5 is an "iterator": is a function can compute a complete list by the mean of releasing one element by call.

An "iteration" is the action of calling an iterator.

Folding a stream is the action of releasing a set of the stream values in an array.

We can see an empty list as a tail of any list as all those notations are equivalent

    1, 2, 3, 4, 5
    1, 2, 3, 4, 5,
    1, 2, 3, 4, 5, ()

So the empty list is used as convention to say that the stream is exhausted. Note that undef is a valid element of a stream. That's why is () maybe called "bound" in this documentation. Note that Perlude functions are using array context to read the iterators so

    return unless $something_to_release

will return () which is a valid way to end the stream

Function composition ^

When relevant, i used the Haskell Prelude documentation descriptions and examples. for example, the take documentation comes from http://hackage.haskell.org/packages/archive/base/latest/doc/html/Prelude.html#v:take

Functions ^

Generators

range $begin, [ $end, [ $step ] ]

A range of numbers from $begin to $end (infinity if $end isn't set) $step by $step.

    range 5     # from 5 to infinity
    range 5,9   # 5, 6, 7, 8, 9
    range 5,9,2 # 5, 7, 9

cycle @set

infinitly loop on a set of values

    cycle 1,4,7

    # 1,4,7,1,4,7,1,4,7,1,4,7,1,4,7,...

records $ref

given any kind of ref that implements the "<>" iterator, returns a Perlude compliant iterator.

    now {print if /data/} records do {
        open my $fh,"foo";
        $fh;
    };

lines

same as records but chomp all records before release.

    now {say if /data/} records do {
        open my $fh,"foo";
        $fh;
    };

filters

filters are composition functions that take a stream and returns a modified stream.

filter

apply

take $n, $xs

take $n, applied to a list $xs, returns the prefix of $xs of length $n, or $xs itself if $n > length $xs:

    sub top10 { take 10, shift }

    take 5, range 1, 10
    # 1, 2, 3, 4, 5, ()

    take 5, range 1, 3
    # 1, 2, 3, ()

takeWhile $predicate, $xs

takeWhile, applied to a predicate $p and a list $xs, returns the longest prefix (possibly empty) of $xs of elements that satisfy $p

    takeWhile { 10 > ($_*2) } range 1,5
    # 1, 2, 3, 4

drop $n, $xs

drop $n $xs returns the suffix of $xs after the first $n elements, or () if $n > length $xs:

    drop 3, range 1,5
    # 4 , 5 

    drop 3, range 1,2
    # ()

dropWhile $predicate, $xs

dropWhile $predicate, $xs returns the suffix remaining after dropWhile $predicate, $xs

     dropWhile { $_ < 3 } unfold [1,2,3,4,5,1,2,3] # [3,4,5,1,2,3]
     dropWhile { $_ < 9 } unfold [1,2,3]           # []
     dropWhile { $_ < 0 } unfold [1,2,3]           # [1,2,3]

misc

unfold $array

unfold returns an iterator on the $array ref so that every Perlude goodies can be applied. there is no side effect on the referenced array.

    my @lower = fold takeWhile {/data/} unfold $abstract

see also fold

Exhausters

now {actions} $xs

read the $xs stream and execute the {actions} block with the returned element as $_ until the $xs stream exhausts. it also returns the last transformed element so that it can be used to foldl.

(compare it to perl6 "eager" or haskell foldl)

fold $xs

returns the array of all the elements computed by $xs

    say join ',',      take 5, sub { state $x=-2; $x+=2 } # CODE(0x180bad8)
    say join ',', fold take 5, sub { state $x=-2; $x+=2 } # 0,2,4,6,8

see also unfold

nth $xs

returns the nth element of a stream

    say fold nth 5, sub { state $x=1; $x++ }
    # 5

Composers

concat @streams

concat takes a list of streams and returns them as a unique one:

    concat map { unfold [split //] } split /\s*/; 

streams every chars of the words of the text

concatC $stream_of_streams

takes a stream of streams $stream_of_streams and expose them as a single one. A stream of streams is a steam that returns streams.

    concatC { take 3, range $_ } lines $fh

take 3 elements from the range started by the values of $fh, so if $fh contains (5,10), the stream is (5,6,7,10,11,12)

concatM $apply, $stream

applying $apply on each iterations of $stream must return a new stream. concatM expose them as a single stream.

    # ls is a generator for a glob

    sub cat { concatM {lines} ls shift } 
    cat "/tmp/*.conf"

AUTHORS ^

CONTRIBUTORS ^

Burak Gürsoy (cpanization)

ACKNOWLEDGMENTS ^

syntax highlighting: