This and other RFCs are available on the web at
http://dev.perl.org/rfc/
=head1 TITLE
Apply operators component-wise in a list context
=head1 VERSION
Maintainer: Jeremy Howard <[EMAIL PROTECTED]>
Created: 10 August 2000
Last modified: 16 August 2000
Version: 2
Mailing List: [EMAIL PROTECTED]
Number: 82
=head1 ABSTRACT
It is proposed that in a list context, operators are applied
component-wise to their arguments. Furthermore, it is proposed that
this behaviour be extended to functions that do not provide a specific
list context.
=head1 CHANGES
=head2 Since v1
=over 4
=item *
Added the ability to apply an operator to a scalar and a list.
=item *
Added more examples, including text processing examples.
=back
=head1 DESCRIPTION
Currently, operators applied to lists in a list context behave
counter-intuitively:
@b = (1,2,3);
@c = (2,4,6);
@d = @b * @c; # Returns (9) == scalar @b * scalar @c
This RFC proposes that operators in a list context should be applied
component-wise to the elements of their arguments:
@d = @b * @c; # Returns (2,8,18)
If the lists are not of equal length, the shorter lists should be treated
as if they were padded with undefs at the right-hand end. However, this
implicit padding should not cause these elements in the shorter lists to
auto-vivify.
If an operator is used in a list context with one list, and one or more
scalars, the scalars are treated as if they were a list of that scalar:
@b = (1,2,3);
@e = @b * 2; # Returns (2,4,6)
@f = @b * (2,2,2) # Same thing
Functions that do not return a list should be treated in the same way:
@e = (-1,1,-3);
@f = abs(@e); # Returns (1,1,3)
=head1 EXAMPLES
=head2 Text processing
If @first_names contains a list of peoples first names, and @surnames
contains their surnames, this creates a new list that concatenates the
elements of the two lists:
@full_names = @first_names . @surnames;
To quote a number of lines of a message by prefixing them all with '> ':
@quoted_lines = '> ' . @raw_lines;
To create a histogram for a list of scores:
@people = ('adam', 'eve ', 'bob ');
@scores = (7,9,5); # Score for each person
@histogram = '#' x @scores; # Returns ('xxxxxxx','xxxxxxxxx','xxxxx')
print join("\n", @people . ' ' . @histogram);
adam xxxxxxx
eve xxxxxxxxx
bob xxxxx
=head2 Number crunching
This snippet multiplies the absolute values of three arrays together and
sums the results, in a very efficient way:
@b = (1,2,3);
@c = (2,4,6);
@d = (-2,-4,-6);
$sum = reduce ^_+^_, abs(@b * @c + @d);
Lists can be reordered or sliced with list generation functions (RFC 81)
allowing flexible data manipulation:
@a = (3,6,9);
@reverse = (3..1);
@b = @a * @a[@rev]; # (3*9, 6*6, 9*3) = (27,36,27)
Slicing plus array operations makes matrix algebra easy:
@a = (1,2,3,
2,4,6,
3,6,9);
@column1of3 = (1:3:7); # (1,4,7) - every 3rd elem from 1 to 7
@row1of3 = (1..3); # (1,2,3)
$sum_col1_by_row1 =
sum ( @a[@column1of3] * @a[@row1of3] ); # (1*1+2*2+3*3)=14
=head1 IMPLEMENTATION
These operators and functions should be evaluated lazily. For instance:
@b = (1,2,3);
@c = (2,4,6);
@d = (-2,-4,-6);
$sum = reduce ^_+^_, @b * @c + @d;
should be evaluated as if it read:
$sum = 0;
$sum += $b[$_] * $c[$_] + $d[_] for (0..$#a-1));
That is, no temporary list is created, and only one loop is required.
The proposal to handle functions is tricky, since there is currently no
obvious way to see whether a function is going to return a list. For
instance, in the case:
@b = abs(@a);
we either need some kind of more advanced prototyping (or other way of
creating a signature) so that Perl knows to apply abs() to the elements of
@a, or we need to manually change abs to check for list context and Do The
Right Thing.
=head1 REFERENCES
The Mathematica Navigator, Heikki Ruskeepää,
Academic Press, ISBN 0-12-603640-3, p383.
Expression Templates (C++ Implementation):
http://extreme.indiana.edu/~tveldhui/papers/techniques/techniques01.html#l32
Implementation in Perl Data Language:
http://pdl.perl.org
RFC 76: reduce
RFC 23: Higher-order functions
RFC 81: Lazily evaluated list generation functions