|
TITLE |
zip
Synopsis_03 - Summary of Perl 6 Operators
Luke Palmer <luke@luqui.org>
Maintainer: Larry Wall <larry@wall.org> Date: 8 Mar 2004 Last Modified: 25 Feb 2006 Number: 3 Version: 13
Several operators have been given new names to increase clarity and better Huffman-code the language:
-> becomes ., like the rest of the world uses.. becomes ~. Think of it as
``stitching'' the two ends of its arguments together.~ now imposes a string context on its argument,
and + imposes a numeric context (as opposed to being a no-op
in Perl 5). Along the same lines, ? imposes a boolean context,
and * imposes a list context.+, ~, or ?.
For example, | becomes either +| or ~| or ?|, depending on
whether the operands are to be treated as numbers, strings, or boolean
values. Left shift << becomes +< , and correspondingly with
right shift. Unary ~ becomes either +^ or ~^ or ?^, since a
bitwise NOT is like an exclusive-or against solid ones. Note that ?^
is functionally identical to !. ?| differs from || in that
?| always returns a standard boolean value (either 1 or 0), whereas
|| return the actual value of the first of its arguments that is
true.x splits into two operators: x (which concatenates repetitions
of a string to produce a single string), and xx (which creates a list of
repetitions of a list or scalar).? : becomes ?? !!.qw{ ... } gets a synonym: < ... >, and an interpolating
variant, «...».
For those still living without the blessings of Unicode, that can also be
written: << ... >>., now constructs a List reference of its
operands. You have to use a [-1] subscript to get the last one... flipflop operator is now done with
ff operator. (.. now always produces a Range object
even in scalar context.) The ff operator may take a caret on
either end to exclude either the beginning or ending. There is
also a corresponding fff operator with Perl 5's ... semantics.
// is just like ||, except that it tests its left
side for definedness instead of truth. There is a low-precedence form,
too: err.=== tests type and value correspondence: for two value types,
tests whether they are the same value (eg. 1 === 1); for two reference
types, checks whether they have the same identity value. For reference
types that do not define an identity, the reference itself is used (eg. it
is not true that [1,2] === [1,2], but it is true that \@a === \@a).
Any reference type may pretend to be a value type by defining a .id method.
(It may also overload infix:<===> for more efficient comparison of
any two objects of that type, but it had better return the same result as if
the two identity values had been generated and compared.) Two values are
never equivalent unless they are of exactly the same type. By contrast,
eq always coerces to string, while == always coerces to numeric.
In fact, $a eq $b really means ``~$a === ~$b'' and $a == $b means
``+$a === +$b.eq semantics by default,
object hashes use === semantics.
=> is no longer just a ``fancy comma.'' It now
constructs a Pair object that can, among other things, be used to
pass named arguments to functions. It provides scalar context to both sides.
Its precedence is now equivalent to assignment, and it is right associative.^^ is the high-precedence version of xor.=~ becomes the ``smart match'' operator ~~, with a whole new set
of semantics. Anywhere you used =~ before you now use ~~, but ~~ is
much more general now. See Synopsis 4 for details. (To catch ``brainos'',
the Perl 6 parser defines an infix:<=~> macro which always fails at
compile time with a message directing the user either to use ~~ or ~= instead,
or to put a space between if they really wanted to assign a stringified value.). calls its single argument (which must be a method, or a
dereferencer for a hash or array) on $_... range operator has variants with ^ on either
end to indicate exclusion of that endpoint from the range. It always
produces a Range object. Range objects are lazy iterators, and can
be interrogated for their current .min and .max values (which
change as they are iterated). Ranges are not autoreversing: 2..1
is always a null range, as is 1^..^2. To reverse a range use:
2..1:by(-1)
reverse 1..2
(The reverse is preferred because it works for alphabetic ranges
as well.)
Because Range objects are lazy, they do not automatically generate
a list. So smart matching against a Range object smartmatches the
endpoints in the domain of the object being matched, so 1.5 ~~
1^..^2 is true. (But 2.1 ~~ 1..2 is false.)
^ operator generates a range from 0 up to
one less than its argument. so ^4 is short for 0..^4 or 0..3.
for ^4 { say $_ } # 0, 1, 2, 3
... is a unary postfix operator that constructs a semi-infinite
(and lazily evaluated) list, starting at the value of its single argument.... as a term is the ``yada, yada, yada'' operator,
which is used as the body in function prototypes. It complains
bitterly (by calling fail) if it is ever executed. Variant
??? calls warn, and !!! calls die.. method invocation, there are
variants .*, .?, and .+ to control how multiple parent methods
of the same name are handled. The .= operator does inplace modification
of the object on the left. The .^ operator calls a class metamethod.= reads lines from a filehandle or filename, or in general
iterates an iterator.
The Unicode characters » (\x[BB]) and « (\x[AB]) and
their ASCII digraphs >> and << are used to denote
``list operations'', which operate on each element of two lists (or
arrays) and return a list (or array) of the results. Spaces are not
allowed on the ``pointy'' end of each ``hyper'', but are allowed on the
blunt end. For example:
(1,1,2,3,5) »+« (1,2,3,5,8); # (2,3,5,8,13)
If one argument is insufficiently dimensioned, Perl ``upgrades'' it:
(3,8,2,9,3,8) >>-<< 1; # (2,7,1,8,2,7)
When using a unary operator, only put it on the operand's side:
@negatives = -« @positives;
@positions »++; # Increment all positions
@objects ».run();
("f","oo","bar")».chars; # (1,2,3)
Note that method calls are really postfix operators, not infix, so you
shouldn't put a « after the dot.
Hyper operators are defined recursively on array references, so:
-« [[1, 2], 3] # [-«[1, 2], -«3]
# == [[-1, -2], -3]
[[1, 2], 3] »+« [4, [5, 6]] # [[1,2] »+« 4, 3 »+« [5, 6]]
# == [[5, 6], [8, 9]]
The other metaoperator in Perl 6 is the reduction operator. Any binary operator can be surrounded by square brackets in term position to create a list operator that reduces using that operation:
[+] 1, 2, 3; # 1 + 2 + 3 = 6
my @a = (5,6);
[*] @a; # 5 * 6 = 30
The reduction associates the same way as the operator used:
[-] 4, 3, 2; # 4-3-2 = (4-3)-2 = -1
[**] 4, 3, 2; # 4**3**2 = 4**(3**2) = 262144
For list-associating operators (like <), all arguments are taken
together, just as if you had written it out explicitly:
[<] 1, 3, 5; # 1 < 3 < 5
If no arguments are given, the operator calls fail (returning
undef, or throwing an exception if use fatal is in effect). If
exactly one argument is given, it is returned by default. However, this
default doesn't make sense for an operator like < that doesn't
return the same type as it takes, so these kinds of operators overload
the single-argument case to return something more meaningful. All the
comparison operators return truth in this case.
This metaoperator can also be used on the semicolon second-dimension separator:
[[;] 1,2,3] # equivalent to [1;2;3]
|, &, and ^ are no longer bitwise operators (see Operator Renaming) but now serve a much higher cause: they are now the
junction constructors.
A junction is a single value that is equivalent to multiple values. They thread through operations, returning another junction representing the result:
(1|2|3) + 4; # 5|6|7
(1|2) + (3&4); # (4|5) & (5|6)
Note how when two junctions are applied through an operator, the result is a junction representing the operator applied to each combination of values.
Junctions come with the functional variants any, all, one, and none.
This opens doors for constructions like:
unless $roll == any(1..6) { print "Invalid roll" }
if $roll == 1|2|3 { print "Low roll" }
Junctions work through subscripting:
print if @foo[any(1,2,3)]
Junctions are specifically unordered. So if you say
for all(@foo) {...}
it indicates to the compiler that there is no coupling between loop iterations and they can be run in any order or even in parallel.
Perl 6 supports the natural extension to the comparison operators, allowing multiple operands.
if 3 < $roll <= 6 { print "High roll" }
if 1 <= $roll1 == $roll2 <= 6 { print "Doubles!" }
Note: any operator beginning with < must have whitespace
in front of it, or it will be interpreted as a hash subscript instead.
A new form of assignment is present in Perl 6, called ``binding,'' used in
place of typeglob assignment. It is performed with the := operator.
Instead of replacing the value in a container like normal assignment, it
replaces the container itself. For instance:
my $x = 'Just Another';
my $y := $x;
$y = 'Perl Hacker';
After this, both $x and $y contain the string ``Perl Hacker,'' since
they are really just two different names for the same variable.
There is another variant, spelled ::=, that does the same thing at
compile time.
There is also an identity test, =:=, which tests whether two names
are bound to the same underlying variable. $x =:= $y would return
true in the above example.
Since typeglobs are being removed, unary * may now serve as a
lazy list flattening operator. It is used to ``flatten'' an Array
(or List) into the List being constructed for the current call,
usually to allow the array's contents to be used as the arguments of
a subroutine call. Note that those arguments still must comply with
the subroutine's signature, but the presence of * defers that test
until run time for that argument (and for any subsequent arguments):
my @args = (\@foo, @bar);
push *@args;
is equivalent to:
push @foo, @bar;
as is this:
my $args = \(@foo, @bar); # construct List object
push *$args;
In list context, a scalar reference to an array does not flatten. Hence
$bar = @bar;
push @foo, $bar;
merely pushes a single scalar reference onto @foo. You can
explicitly flatten it in any of these ways:
push @foo, *$bar;
push @foo, @$bar;
push @foo, $bar[];
(The * in list context doesn't change the call semantics as it
does in scalar context.) Note that these three forms also allow you
to specify list context on assignment:
*$bar = (1,2,3);
@$bar = (1,2,3);
$bar[] = (1,2,3);
The last is particularly useful at the end of a long name naming an array attribute:
$foo.bar.baz.bletch.whatever.attr[] = (1,2,3)
The empty [] and .[] postfix operators are interpreted as
zero-dimensional slices returning the entire array, not null slices
returning no elements. Likewise for {} and .{} on hashes,
not to mention the <>, .<>, «», and .«»
constant and interpolating slice subscripting forms.
The * operator flattens lazily. To get an immediate flattening like
Perl 5 does, use unary ** instead. You may use either of them on
a scalar iterator to force it to iterate.
The new operators ==> and <== are akin to UNIX pipes, but
work with functions that accept and return lists. For example,
@result = map { floor($^x / 2) }
grep { /^ \d+ $/ }
@data;
Can also now be written:
@data ==> grep { /^ \d+ $/ }
==> map { floor($^x / 2) }
==> @result;
or:
@result <== map { floor($^x / 2) }
<== grep { /^ \d+ $/ }
<== @data;
Either form more clearly indicates the flow of data. See Synopsis 6 for more of the (less-than-obvious) details on these two operators.
An appended : marks the invocant when using the indirect-object
syntax for Perl 6 method calls. The following two statements are
equivalent:
$hacker.feed('Pizza and cola');
feed $hacker: 'Pizza and cola';
A colon may also be used on an ordinary method call to indicate that it should be parsed as a list operator:
$hacker.feed: 'Pizza and cola';
zipIn order to support parallel iteration over multiple arrays, Perl 6 has
a zip function that builds tuples of the elements of two or more arrays.
for zip(@names; @codes) -> [$name, $zip] {
print "Name: $name; Zip code: $zip\n";
}
zip has an infix synonym, the Unicode operator ¥.
To read arrays in parallel like zip but just sequence the values
rather than generating tuples, use each instead of zip.
for each(@names; @codes) -> $name, $zip {
print "Name: $name; Zip code: $zip\n";
}
The each function reads to the end of the longest list, not counting
lists that are known to be infinite such as 0..Inf. Missing values
are replaced with undef. In contrast, use roundrobin if you just
wish to skip missing entries:
for roundrobin(@queue1; @queue2; @queue3) -> $next {
...
}
To read arrays serially rather than in parallel, use cat(@x;@y).
Whitespace is no longer allowed before the opening bracket of an array or hash accessor. That is:
%monsters{'cookie'} = Monster.new; # Valid Perl 6
%people {'john'} = Person.new; # Not valid Perl 6
One of the several useful side-effects of this restriction is that parentheses are no longer required around the condition of control constructs:
if $value eq $target {
print "Bullseye!";
}
while 0 < $i { $i++ }
It is, however, still possible to align accessors by explicitly using the .
operator:
%monsters.{'cookie'} = Monster.new;
%people .{'john'} = Person .new;
%cats .{'fluffy'} = Cat .new;
Perl 6 has 22 precedence levels (which is fewer than Perl 5):
terms 42 "eek" $x /abc/ (1+2) a(1) :by(2) .meth listop
method postfix . .+ .? .* .() .[] .{} .«» .=
autoincrement ++ --
exponentiation **
symbolic unary ! + - ~ ? * ** +^ ~^ ?^ \ ^
multiplicative * / % x xx +& +< +> ~& ~< ~>
additive + - ~ +| +^ ~| ~^
junctive and (all) &
junctive or (any) | ^
named unary rand sleep abs etc.
nonchaining binary but does cmp <=> .. ^.. ..^ ^..^ ff ^ff ff^ ^ff^ fff ^fff etc.
chaining binary != == < <= > >= ~~ !~ eq ne lt le gt ge =:= ===
tight and &&
tight or || ^^ //
ternary ?? !!
assignment = := ::= += -= **= xx= etc. (and also =>)
list item separator , ¥
list op (rightward) <== print push any all true not etc.
pipe forward ==>
loose and and
loose or or xor err
expr terminator ; {} as control block, statement modifiers
|
TITLE |