Array-APX

 view release on metacpan or  search on metacpan

lib/Array/APX.pm  view on Meta::CPAN

    my ($left, $right) = @_;

    if ((ref($left) eq __PACKAGE__ and ref($right) eq __PACKAGE__) or
        (ref($left) eq __PACKAGE__ and defined($right) and !ref($right))
       ) # Binary or
    {
        my ($self, $other) = @_;
        my $result = ref($right) ? [@$right] : [$right];
        Array::DeepUtils::binary([@$left], $result, sub { $_[0] | $_[1] }, 1);
        return bless $result;
    }
    # If the right side argument is a reference to a subroutine we are at
    # the initial stage of a |...|-operator and have to rememeber the 
    # function to be used as well as the left hand operator:
    elsif (ref($left) eq __PACKAGE__ and ref($right) eq 'CODE')
    {
        my %outer;
        $outer{left}     = $left;  # APX object
        $outer{operator} = $right; # Reference to a subroutine
        push @_outer_stack, \%outer;
        return;
    }
    elsif (ref($left) eq __PACKAGE__ and !defined($right))
    {   # Second phase of applying the |...|-operator:
        my $info = pop @_outer_stack;
        my ($a1, $a2) = ([@{$info->{left}}], [@{$left}]);
        my @result;

        for my $i ( 0 .. @$a1 - 1 )
        {
            for my $j ( 0 .. @$a2 - 1 )
            {
                my $value = $a2->[$j];
                _binary($a1->[$i], $value, $info->{operator});
                $result[$i][$j] = $value;
            }
        }

        return bless \@result;
    }

    croak 'outer: Strange parametertypes: >>', ref($left), 
          '<< and >>', ref($right), '<<';
}

=head2 The reduce operator /

The operator / acts as the reduce operator if applied to a reference to a 
subroutine as its left argument and an APX structure as its right element:

    use strict;
    use warnings;
    use Array::APX qw(:all);

    my $x = iota(100) + 1;
    my $f = sub { $_[0] + $_[1] };

   print $f/ $x, "\n";

calculates the sum of all integers between 1 and 100 (without using Gauss'
summation formula just by repeated addition). The combined operator

    $f/

applies the function referenced by $f between each two successive elements 
of the APX structure on the right hand side of the operator.

=cut

sub reduce
{
    my ($left, $right, $swap) = @_;

    if (ref($left) eq __PACKAGE__ and ref($right) ne 'CODE') # Binary division
    {
         my $result = ref($right) ? [@$right] : [$right];
         ($left, $result) = ($result, [@$left]) if $swap;
        _binary([@$left], $result, sub { $_[0] / $_[1] }, 1);
        return bless $result;
    }
    elsif (ref($_[0]) eq __PACKAGE__ and ref($_[1]) eq 'CODE') # reduce operator
    {
        my $result = shift @$left;
        for my $element (@$left)
        {
            eval { _binary($element, $result, $right); };
            croak "reduce: Error while applying reduce: $@\n" if $@;
        }

        return $result;
    }

    croak 'outer: Strange parametertypes: ', ref($_[0]), ' and ', ref($_[0]);
}

=head2 The scan operator x

The scan-operator works like the \-operator in APL - it applies a binary 
function to all successive elements of an array but accumulates the results
gathered along the way. The following example creates a vector of the 
partial sums of 0, 0 and 1, 0 and 1 and 2, 0 and 1 and 2 and 3 etc.:

    $f = sub { $_[0] + $_[1] };
    $x = $f x iota(10);
    print $x;

This code snippet yields the following result:

    [    0    1    3    6   10   15   21   28   36   45 ]

=cut

sub scan
{
    my ($argument, $function, $swap) = @_;

    croak "scan operator: Wrong sequence of function and argument!\n"
        unless $swap;

    croak "scan operator: No function reference found!\n"
        if ref($function) ne 'CODE';



( run in 2.118 seconds using v1.01-cache-2.11-cpan-13bb782fe5a )