#!/usr/bin/perl -w

use strict;

=head1 NAME

mapcar - splice a list of lists, and a version of map for hashes

=head1 SYNOPSIS

 @a = (1, 2, 3);
 @b = qw(Mary Jane);
 @c = ('A' .. 'E');
 %d = ( smokey => 1,
        cheese => 6,
        fire   => 7,
        plant  => 3.5 );

 @spliced = mapcar { [ @_ ] } (\@a, \@b, \@c);

 @mixed  = mapcaru { [ @_ ] } (\@a, \@b, \@c);

 %hashed = mapeach { ( $_[0] > 4 ? @_ : () ) } %d;

=head2 Results after the above

 @spliced = ([1,     "Mary", "A"],
             [2,     "Jane", "B"],
             [3,     undef,  "C"],
             [undef, undef,  "D"],
             [undef, undef,  "E"]);

 @mixed   = ([1,     "Mary", "A"],
             [2,     "Jane", "B"],
             [3,             "C"],
             [               "D"],
             [               "E"]);

 %hashed = ( cheese => 6,
             fire   => 7 );

=head1 DESCRIPTION

"mapcar", "mapcaru" originated in LISP (the LISt Processing language).
So did the Perl built-in function "map".

map_iter
map_head

=cut

package mapcar;
require Exporter;
use vars qw( $VERSION @EXPORT @ISA );

BEGIN {
    $VERSION= 1.02;
    @EXPORT= qw( mapcar mapcaru mapeach );
    @ISA= qw( Exporter );
}

sub mapcaru (&@)
{
    my $sub= shift;
    if(  ! @_  ) {
        require Carp;
        Carp::croak( "mapcaru: Nothing to map" );
    }
    my $max= 0;
    for my $av (  @_  ) {
        if(  ! UNIVERSAL::isa( $av, "ARRAY" )  ) {
            require Carp;
            Carp::croak( "mapcaru: Not an array reference (",
                ref($av) ? ref($av) : $av, ")" );
        }
        $max= @$av   if  $max < @$av;
    }
    my @ret;
    for(  my $i= 0;  $i < $max;  $i++  ) {
        push @ret, &$sub( map { $_->[$i] } @_ );
    }
    return wantarray ? @ret : \@ret;
}

sub mapcar (&@)
{
    my $sub= shift;
    if(  ! @_  ) {
        require Carp;
        Carp::croak( "mapcar: Nothing to map" );
    }
    my $max= 0;
    for my $av (  @_  ) {
        if(  ! UNIVERSAL::isa( $av, "ARRAY" )  ) {
            require Carp;
            Carp::croak( "mapcar: Not an array reference (",
                ref($av) ? ref($av) : $av, ")" );
        }
        $max= @$av   if  $max < @$av;
    }
    my @ret;
    for(  my $i= 0;  $i < $max;  $i++  ) {
        push @ret, &$sub( map { $i < @$_ ? $_->[$i] : () } @_ );
    }
    return wantarray ? @ret : \@ret;
}

sub mapeach (&;@)
{
    my $sub = shift;

    map { UNIVERSAL::isa($_, "HASH") or do {
        require Carp;
        Carp::croak( "mapeach: Not a hash reference (",
		     (ref($_) || $_) . ")" );
    }; } @_;

    my $a;
    map { $sub->(@$a) } while ( $a = [ each %{$_[0]} ]);
}

1;


