Categories
Posts in this category
- Introduction
- Strings, Arrays, Hashes;
- Types
- Basic Control Structures
- Subroutines and Signatures
- Objects and Classes
- Contexts
- Regexes (also called "rules")
- Junctions
- Comparing and Matching
- Containers and Values
- Where we are now - an update
- Changes to Perl 5 Operators
- Laziness
- Custom Operators
- The MAIN sub
- Twigils
- Enums
- Unicode
- Scoping
- Regexes strike back
- A grammar for (pseudo) XML
- Subset Types
- The State of the implementations
- Quoting and Parsing
- The Reduction Meta Operator
- The Cross Meta Operator
- Exceptions and control exceptions
- Common Perl 6 data processing idioms
- Currying
Thu, 22 Jul 2010
Common Perl 6 data processing idioms
Permanent link
NAME
"Perl 5 to 6" Lesson 27 - Common Perl 6 data processing idioms
SYNOPSIS
# create a hash from a list of keys and values: # solution 1: slices my %hash; %hash{@keys} = @values; # solution 2: meta operators my %hash = @keys Z=> @values; # create a hash from an array, with # true value for each array item: my %exists = @keys X=> True; # limit a value to a given range, here 0..10. my $x = -2; say 0 max $x min 10; # for debugging: dump the contents of a variable, # including its name, to STDERR note :$x.perl; # sort case-insensitively say @list.sort: *.lc; # mandatory attributes class Something { has $.required = die "Attribute 'required' is mandatory"; } Something.new(required => 2); # no error Something.new() # BOOM
DESCRIPTION
Learning the specification of a language is not enough to be productive with it. Rather you need to know how to solve specific problems. Common usage patterns, called idioms, helps you not having to re-invent the wheel every time you're faced with a problem.
So here a some common Perl 6 idioms, dealing with data structures.
Hashes
# create a hash from a list of keys and values: # solution 1: slices my %hash; %hash{@keys} = @values; # solution 2: meta operators my %hash = @keys Z=> @values;
The first solution is the same you'd use in Perl 5: assignment to a slice. The second solution uses the zip operator Z
, which joins to list like a zip fastener: 1, 2, 3 Z 10, 20, 30
is 1, 10, 2, 20, 3, 30
. The Z=>
is a meta operator, which combines zip with =>
(the Pair construction operator). So 1, 2, 3 Z=> 10, 20, 30
evaluates to 1 => 10, 2 => 20, 3 => 30
. Assignment to a hash variable turns that into a Hash.
For existence checks, the values in a hash often doesn't matter, as long as they all evaluate to True
in boolean context. In that case, a nice way to initialize the hash from a given array or list of keys is
my %exists = @keys X=> True;
which uses the cross meta operator to use the single value True
for every item in @keys
.
Numbers
Sometimes you want to get a number from somewhere, but clip it into a predefined range (for example so that it can act as an array index).
In Perl 5 you often end up with things like $a = $b > $upper ? $upper : $b
, and another conditional for the lower limit. With the max
and min
infix operators, that simplifies considerably to
my $in-range = $lower max $x min $upper;
because $lower max $x
returns the larger of the two numbers, and thus clipping to the lower end of the range.
Since min
and max
are infix operators, you can also clip infix:
$x max= 0; $x min= 10;
Debugging
Perl 5 has Data::Dumper, Perl 6 objects have the .perl
method. Both generate code that reproduces the original data structure as faithfully as possible.
:$var
generates a Pair ("colonpair"), using the variable name as key (but with sigil stripped). So it's the same as var => $var
. note()
writes to the standard error stream, appending a newline. So note :$var.perl
is quick way of obtaining the value of a variable for debugging; purposes, along with its name.
Sorting
Like in Perl 5, the sort
built-in can take a function that compares two values, and then sorts according to that comparison. Unlike Perl 5, it's a bit smarter, and automatically does a transformation for you if the function takes only one argument.
In general, if you want to compare by a transformed value, in Perl 5 you can do:
# WARNING: Perl 5 code ahead my @sorted = sort { transform($a) cmp transform($b) } @values; # or the so-called Schwartzian Transform: my @sorted = map { $_->[1] } sort { $a->[0] cmp $b->[0] } map { [transform($_), $_] } @values
The former solution requires repetitive typing of the transformation, and executes it for each comparison. The second solution avoids that by storing the transformed value along with the original value, but it's quite a bit of code to write.
Perl 6 automates the second solution (and a bit more efficient than the naiive Schwartzian transform, by avoiding an array for each value) when the transformation function has arity one, ie accepts one argument only:
my @sorted = sort &transform, @values;
Mandatory Attributes
The typical way to enforce the presence of an attribute is to check its presence in the constructor - or in all constructors, if there are many.
That works in Perl 6 too, but it's easier and safer to require the presence at the level of each attribute:
has $.attr = die "'attr' is mandatory";
This exploits the default value mechanism. When a value is supplied, the code for generating the default value is never executed, and the die
never triggers. If any constructor fails to set it, an exception is thrown.
MOTIVATION
N/A