Author: lwall
Date: 2010-03-15 18:39:10 +0100 (Mon, 15 Mar 2010)
New Revision: 30092
Modified:
docs/Perl6/Spec/S03-operators.pod
Log:
[S03] add Z to go with X metaop
note that X and Z desugar to higher-order methods, crosswith and zipwith
speculate about how to zip/cross dwimmily with non-identical ops
possibly creating a real use case for surreal precedence :)
Modified: docs/Perl6/Spec/S03-operators.pod
===================================================================
--- docs/Perl6/Spec/S03-operators.pod 2010-03-15 17:02:04 UTC (rev 30091)
+++ docs/Perl6/Spec/S03-operators.pod 2010-03-15 17:39:10 UTC (rev 30092)
@@ -15,8 +15,8 @@
Created: 8 Mar 2004
- Last Modified: 2 Mar 2010
- Version: 196
+ Last Modified: 15 Mar 2010
+ Version: 197
=head1 Overview
@@ -1732,6 +1732,9 @@
1,2 Z 3,4 # (1,3),(2,4)
+The C<Z> operator is actually a degenerate case of the C<Z> zipwith
+metaoperator (see L<Zip operators> below).
+
=item *
C<< infix:<minmax> >>, the minmax operator
@@ -3841,14 +3844,16 @@
operators yourself. Similarly, the carets that exclude the endpoints
on ranges are there by convention only.
-In contrast to that, Perl 6 has seven standard metaoperators for
+In contrast to that, Perl 6 has eight standard metaoperators for
turning a given existing operator into a related operator that is
more powerful (or at least differently powerful). These differ from a
mere naming convention in that Perl automatically generates these new
operators from user-defined operators as well as from builtins.
In fact, you're not generally supposed to define the individual
metaoperations--their semantics are supposed to be self-evident by
-the transformation of the base operator.
+the transformation of the base operator. In other words, these
+metaoperators are really just shorthand for higher-order functions
+(functions that take other functions as arguments).
Constructs containing metaoperators are considered "metatokens",
by which we mean that they are not subject to ordinary longest-token
@@ -4396,19 +4401,33 @@
=head2 Cross operators
The cross metaoperator, C<X>, may be followed by any infix operator.
-It applies the
-modified operator across all groupings of its list arguments as returned
-by the ordinary C<< infix:<X> >> operator. All
-generated cross operators are of list infix precedence, and are list
associative.
+It applies the modified operator across all groupings of its list
+arguments as returned by the ordinary C<< infix:<X> >> operator.
+All generated cross operators are of list infix precedence, and are
+list associative.
The string concatenating form is:
- <a b> X~ <1 2> # 'a1', 'a2', 'b1', 'b2'
+ <a b> X~ 1,2 # 'a1', 'a2', 'b1', 'b2'
-The C<X~> operator desugars to something like:
+The C<X~> operator desugars to:
- [~]«( <a b> X, <1 2> ) # 'a1', 'a2', 'b1', 'b2'
+ (<a b>; 1,2).crosswith(&[~])
+which in turn means
+
+ (<a b>; 1,2).cross.slice.map { .reduce(&[~]) }
+
+And
+
+ <a b> X~ 1,2 X+ 3,4
+
+might mean
+
+ (<a b>; 1,2; 3,4).cross.slice.map { .reduce(&[~],&[+]) }
+
+(But see below.)
+
The list concatenating form, C<X,>, when used like this:
<a b> X, 1,2 X, <x y>
@@ -4424,7 +4443,8 @@
('b', 2, 'x'),
('b', 2, 'y')
-The list form is common enough to have a shortcut, the ordinary infix
+The C<X,> operator is perhaps more clearly written as C<X[,]>. However,
+this list form is common enough to have a shortcut, the ordinary infix
C<X> operator described earlier.
For the general form, any existing, non-mutating infix operator
@@ -4447,8 +4467,85 @@
Note that only the first term of an C<X> operator may reasonably be
an infinite list.
-Multidimensional lists should be handled properly.
+All lists are assumed to be flat; multidimensional lists are
+handled by treating the first dimension as the only dimension.
+=head2 Zip operators
+
+The zip metaoperator, C<Z>, may be followed by any infix operator.
+It applies the modified operator across all groupings of its list
+arguments as returned by the ordinary C<< infix:<Z> >> operator.
+All generated zip operators are of list infix precedence, and are
+list associative.
+
+The string concatenating form is:
+
+ <a b> Z~ 1,2 # 'a1', 'b2'
+
+The C<Z~> operator desugars to:
+
+ (<a b>; 1,2).zipwith(&[~])
+
+which in turn means
+
+ (<a b>; 1,2).zip.slice.map { .reduce(&[~]) }
+
+And
+
+ <a b> Z~ 1,2 Z+ 3,4 # 'a4', 'b6'
+
+would mean
+
+ (<a b>; 1,2; 3,4).zip.slice.map { .reduce(&[~],&[+]) }
+
+implying that multi-function reduce knows how to compare the precedence
+of its operator arguments somehow. That seems unreasonable. The clean
+way to solve this might involve giving C<X> and C<Z> metaoperators a
+subprecedence within listop precedence corresponding to the original
+operator's precedence, so that C<Z~> and C<Z+> actually have different
+precedences within listop precedence. Then the above would parse as if
+you'd said C<< <a b> Z~ ( 1,2 Z+ 3,4> ) >>, but the lists would still
+parse at list infix precedence, with comma tighter than the zips.
+(This would actually be fairly trivial to implement, given how we
+represent our precedence as strings.) Also, though it's complicated to
+explain, subprecedence within C<Z> might be exactly what the naive user
expects.
+
+The list concatenating form, C<Z,>, when used like this:
+
+ <a b> Z, 1,2 Z, <x y>
+
+produces
+
+ ('a', 1, 'x'),
+ ('b', 2, 'y')
+
+The C<Z,> operator is perhaps more clearly written as C<Z[,]>. However,
+this list form is common enough to have a shortcut, the ordinary infix
+C<Z> operator described earlier.
+
+For the general form, any existing, non-mutating infix operator
+may be used.
+
+ 1,2 Z* 3,4 # 3,8
+
+(Note that C<< <== >> and C<< ==> >> are considered mutating, as well as
+all assignment operators.)
+
+If the underlying operator is non-associating, so is the cross operator:
+
+ @a Zcmp @b Zcmp @c # ILLEGAL
+ @a Zeq @b Zeq @c # ok
+
+In fact, though the C<Z> operators are all list associative
+syntactically, the underlying operator is always applied with its
+own associativity, just as the corresponding reduce operator would do.
+
+Note that, unlike the C<X> operator, all the terms of a C<Z> operator
+may reasonable be infinite lists, since zipping is lazy.
+
+All lists are assumed to be flat; multidimensional lists are
+handled by treating the first dimension as the only dimension.
+
=head2 Sequential operators
The sequence metaoperator, C<S>, may be followed by any non-fiddly infix
operator.