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.