Exegesis 3
Operators
by Damian ConwayOctober 03, 2001
Editor's note: this document is out of date and remains here for historic interest. See Synopsis 3 for the current design information.
Diamond lives (context-aware);
Underscore space means concatenate; fat comma means pair;
A pre-star will flatten; colon-equals will bind;
And binary slash-slash yields left-most defined.-- Sade, "Smooth operator" (Perl 6 remix)
In Apocalypse 3, Larry describes the changes that Perl 6 will make to operators and their operations. As with all the Apocalypses, only the new and different are presented -- just remember that the vast majority of operator-related syntax and semantics will stay precisely as they are in Perl 5.
For example...
To better understand those new and different aspects of Perl 6 operators, let's consider the following program. Suppose we wanted to locate a particular data file in one or more directories, read the first four lines of each such file, report and update their information, and write them back to disk.
|
Related Reading
Programming Perl, 3rd Edition |
We could do that with this:
sub load_data ($filename ; $version, *@dirpath) {
$version //= 1;
@dirpath //= @last_dirpath // @std_dirpath // '.';
@dirpath ^=~ s{([^/])$}{$1/};
my %data;
foreach my $prefix (@dirpath) {
my $filepath = $prefix _ $filename;
if (-w -r -e $filepath and 100 < -s $filepath <= 1e6) {
my $fh = open $filepath : mode=>'rw'
or die "Something screwy with $filepath: $!";
my ($name, $vers, $status, $costs) = <$fh>;
next if $vers < $version;
$costs = [split /\s+/, $costs];
%data{$filepath}{qw(fh name vers stat costs)} =
($fh, $name, $vers, $status, $costs);
}
}
return %data;
}
my @StartOfFile is const = (0,0);
sub save_data ( %data) {
foreach my $data (values %data) {
my $rest = <$data.{fh}.irs(undef)>
seek $data.{fh}: *@StartOfFile;
truncate $data.{fh}: 0;
$data.{fh}.ofs("\n");
print $data.{fh}: $data.{qw(name vers stat)}, _@{$data.{costs}}, $rest;
}
}
my %data = load_data(filename=>'weblog', version=>1);
my $is_active_bit is const = 0x0080;
foreach my $file (keys %data) {
print "$file contains data on %data{$file}{name}\n";
%data{$file}{stat} = %data{$file}{stat} ~ $is_active_bit;
my @costs := @%data{$file}{costs};
my $inflation;
print "Inflation rate: " and $inflation = +<>
until $inflation != NaN;
@costs = map { $_.value }
sort { $a.key <=> $b.key }
map { amortize($_) => $_ }
@costs ^* $inflation;
my sub operator:∑ is prec(\&operator:+($)) (*@list : $filter //= undef) {
reduce {$^a+$^b} ($filter ?? grep &$filter, @list :: @list);
}
print "Total expenditure: $( ∑ @costs )\n";
print "Major expenditure: $( ∑ @costs : {$^_ >= 1000} )\n";
print "Minor expenditure: $( ∑ @costs : {$^_ < 1000} )\n";
print "Odd expenditures: @costs[1..Inf:2]\n";
}
save_data(%data, log => {name=>'metalog', vers=>1, costs=>[], stat=>0});
I was bound under a flattening star
The first subroutine takes a filename and (optionally) a version number and a list of directories to search:
sub load_data ($filename ; $version, *@dirpath) {
Note that the directory path parameter is declared as *@dirpath,
not
@dirpath. In Perl 6, declaring a parameter as an array (i.e
@dirpath)
causes Perl to expect the corresponding argument will be an actual array
(or an array reference), not just any old list of values. In other words,
a @ parameter in Perl 6 is like a \@ context specifier
in Perl 5.
To allow @dirpath to accept a list of arguments, we have to use the list context specifier -- unary * -- to tell Perl to "slurp up" any remaining arguments into the @dirpath parameter.
This slurping-up process consists of flattening any arguments that are arrays or hashes, and then assigning the resulting list of values, together with any other scalar arguments, to the array (i.e. to @dirpath in this example). In other words, a *@ parameter in Perl 6 is like a @ context specifier in Perl 5.






