=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 -- print(join(' ', qw(Casey R. Tweten)));my $sig={mail=>'[EMAIL PROTECTED]',site=> 'http://home.kiski.net/~crt'};print "\n",'.'x(length($sig->{site})+6),"\n"; print map{$_.': '.$sig->{$_}."\n"}sort{$sig->{$a}cmp$sig->{$b}}keys%{$sig}; my $VERSION = '0.01'; #'patched' by Jerrad Pierce <belg4mit at MIT dot EDU>