Author: larry
Date: Fri Apr  7 11:53:34 2006
New Revision: 8607

Modified:
   doc/trunk/design/syn/S03.pod

Log:
Reduce now defined directly in terms of list operators, possibly autogenerated.


Modified: doc/trunk/design/syn/S03.pod
==============================================================================
--- doc/trunk/design/syn/S03.pod        (original)
+++ doc/trunk/design/syn/S03.pod        Fri Apr  7 11:53:34 2006
@@ -12,9 +12,9 @@
 
   Maintainer: Larry Wall <[EMAIL PROTECTED]>
   Date: 8 Mar 2004
-  Last Modified: 5 Apr 2006
+  Last Modified: 7 Apr 2006
   Number: 3
-  Version: 17
+  Version: 18
 
 =head1 Operator renaming
 
@@ -118,8 +118,9 @@
 compile time with a message directing the user either to use C<~~> or C<~=> 
instead,
 or to put a space between if they really wanted to assign a stringified value.)
 
-=item * Unary C<.> calls its single argument (which must be a method, or a
-dereferencer for a hash or array) on C<$_>.
+=item * "Unary" C<.> calls its single argument (which must be a method, or a
+dereferencer for a hash or array) on C<$_>.  (It's not really a unary operator,
+so we put it in quotes.)
 
 =item * The C<..> range operator has variants with C<^> on either
 end to indicate exclusion of that endpoint from the range.  It always
@@ -146,11 +147,16 @@
 
 =item * C<...> is a unary postfix operator that constructs a semi-infinite
 (and lazily evaluated) list, starting at the value of its single argument.
+It should not have any trailing whitespace, or it will be confused with
+a "long dot".
 
-=item * However, C<...> as a term is the "yada, yada, yada" operator,
-which is used as the body in function prototypes.  It complains
-bitterly (by calling C<fail>) if it is ever executed.  Variant
-C<???> calls C<warn>, and C<!!!> calls C<die>.
+=item * However, C<...> where a term is expected is the "yada,
+yada, yada" prefix operator, which is used as the body in function
+prototypes.  It complains bitterly (by calling C<fail>) if it is
+ever executed.  Variant C<???> calls C<warn>, and C<!!!> calls C<die>.
+The argument is optional, but if provided, is passed onto the C<warn>,
+C<fail>, or C<die>.  Otherwise the system will make up a message for
+you based on the context.
 
 =item * In addition, to the ordinary C<.> method invocation, there are
 variants C<.*>, C<.?>, and C<.+> to control how multiple parent methods
@@ -207,7 +213,44 @@
     my @a = (5,6);
     [*] @a;           # 5 * 6 = 30
 
-The reduction associates the same way as the operator used:
+A reduction operator really is a list operator, and is invoked as one.
+Hence, you maybe implement a reduction operator in one of two ways.  Either
+you can write an explicit list operator:
+
+    proto prefix:<[+]> ([EMAIL PROTECTED]) {
+        my $accum = 0;
+        while (@args) {
+            $accum += @args.shift();
+        }
+        return $accum;
+    }
+
+or you can let the system autogenerate one for you based on the
+corresponding infix operator, probably by currying:
+
+    # (examples, actual system may define prefix:[**] instead)
+    &prefix:<[*]> ::= &reduce.assuming(&infix:<*>, 1);
+    &prefix:<[**]> ::= &reducerev.assuming(&infix:<**>);
+
+As a special form of name, the non-prefix notation, as in
+
+    proto [foo] ([EMAIL PROTECTED]) {
+        ...
+    }
+
+or
+
+    &[foo] ::= ...
+
+defines both the C<[foo]> reduce operator and the C<foo> infix operator.
+Where appropriate, use of the infix form may be optimized like this:
+
+    $a foo $b           ===>    [foo] $a, $b
+    $a foo $b foo $c    ===>    [foo] $a, $b, $c
+    ...                         ...
+
+If the reduction operator is defined separately from the infix operator,
+it must associate 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
@@ -217,85 +260,88 @@
 
     [<] 1, 3, 5;      # 1 < 3 < 5
 
-If fewer than two arguments are given, one MMD attempt is made to
-dispatch to the operator anyway with whatever arguments are given.
-If this multi-dispatch succeeds, the result becomes the result of the
-reduce.
-
-Otherwise, if the dispatch fails, then if there is one argument,
-that argument is returned.  However, this default doesn't make sense
-for an operator like C<< < >> that doesn't return the same type as it
-takes, so these kinds of operators overload the single-argument case
+If fewer than two arguments are given, a dispatch is still attempted
+with whatever arguments are given, and it is up to the receiver of that
+dispatch to deal with fewer than two arguments.  Note that the proto
+list operator definition is the most general, so you are allowed to define
+different ways to handle the one argument case depending on type:
+
+    multi prefix:<[foo]> (Int $x) { 42 }
+    multi prefix:<[foo]> (Str $x) { fail "Can't foo a single Str" }
+
+However, the zero argument case must of necessity be handled by the
+proto version, since there is no type information to dispatch on.
+Operators that wish to specify an identity value should do so by
+specifying the proto listop.  Among the builtin operators, [+]()
+returns 0 and [*]() returns 1, for instance.
+
+By default, if there is one argument, the built-in reduce operators
+return that one argument.  However, this default doesn't make sense
+for operators like C<< < >> that don't return the same type as they
+take, so these kinds of operators overload the single-argument case
 to return something more meaningful.  All the comparison operators
 return a boolean for either 1 or 0 arguments.  Negated operators,
 return Bool::False, and all the rest return Bool::True.
 
-If no arguments were given, and the dispatch to the 0-ary form fails,
-the reduce as a whole fails.  Operators that wish to specify an identity
-value should do so by overloading the 0-ary variant.  Among the builtin
-operators, infix:<+>() returns 0 and infix:<*>() returns 1.  Note that,
-while the single argument form can MMD dispatch based on the type of
-the single argument, the 0-argument form cannot.
-
 This metaoperator can also be used on the semicolon second-dimension
 separator:
 
     [[;] 1,2,3]   # equivalent to [1;2;3]
 
-Builtin infix operators specify the following identity operations:
+Builtin reduce operators return the following identity operations:
 
-    multi sub infix:<**> ()     { 1 }   # arguably nonsensical
-    multi sub infix:<*> ()      { 1 }
-    multi sub infix:</> ()      { ??? } # reduce is nonsensical
-    multi sub infix:<%> ()      { ??? } # reduce is nonsensical
-    multi sub infix:<x> ()      { ??? } # reduce is nonsensical
-    multi sub infix:<xx> ()     { ??? } # reduce is nonsensical
-    multi sub infix:<+&> ()     { +^0 } # -1 on 2's complement machine
-    multi sub infix:{'+<'} ()   { ??? } # reduce is nonsensical
-    multi sub infix:{'+>'} ()   { ??? } # reduce is nonsensical
-    multi sub infix:<~&> ()     { ??? } # sensical but 1's length indeterminate
-    multi sub infix:{'~<'} ()   { ??? } # reduce is nonsensical
-    multi sub infix:{'~>'} ()   { ??? } # reduce is nonsensical
-    multi sub infix:<+> ()      { 0 }
-    multi sub infix:<-> ()      { 0 }
-    multi sub infix:<~> ()      { '' }
-    multi sub infix:<+|> ()     { 0 }
-    multi sub infix:<+^> ()     { 0 }
-    multi sub infix:<~|> ()     { '' } # length indeterminate but 0's default
-    multi sub infix:<~^> ()     { '' } # length indeterminate but 0's default
-    multi sub infix:<&> ()      { all() }
-    multi sub infix:<|> ()      { any() }
-    multi sub infix:<^> ()      { one() }
-    multi sub infix:<!=> ($x?)  { Bool::False }
-    multi sub infix:<==> ($x?)  { Bool::True }
-    multi sub infix:{'<'} ($x?) { Bool::True }
-    multi sub infix:{'<='} ($x?) { Bool::True }
-    multi sub infix:{'>'} ($x?) { Bool::True }
-    multi sub infix:{'>='} ($x?) { Bool::True }
-    multi sub infix:<~~> ($x?)  { Bool::True }
-    multi sub infix:<!~> ($x?)  { Bool::False }
-    multi sub infix:<eq> ($x?)  { Bool::True }
-    multi sub infix:<ne> ($x?)  { Bool::False }
-    multi sub infix:<lt> ($x?)  { Bool::True }
-    multi sub infix:<le> ($x?)  { Bool::True }
-    multi sub infix:<gt> ($x?)  { Bool::True }
-    multi sub infix:<ge> ($x?)  { Bool::True }
-    multi sub infix:<=:=> ($x?) { Bool::True }
-    multi sub infix:<===> ($x?) { Bool::True }
-    multi sub infix:<&&> ()     { Bool::True }
-    multi sub infix:<||> ()     { Bool::False }
-    multi sub infix:<^^> ()     { Bool::False }
-    multi sub infix:<//> ()     { undef }
-    multi sub infix:<,> ()      { () }
-    multi sub infix:<¥> ()      { [] }
-
-Any builtin operator not mentioned here does not have an identity
-value.  User-defined operators may of course define their own
-identity values.  Math packages wishing to find the identity value
-for an operation can call C<infix:{$opname}()> to discover it.
-(There is no explicit identity property.)
+    [**]()      # 1     (arguably nonsensical)
+    [*]()       # 1
+    [/]()       # fail  (reduce is nonsensical)
+    [%]()       # fail  (reduce is nonsensical)
+    [x]()       # fail  (reduce is nonsensical)
+    [xx]()      # fail  (reduce is nonsensical)
+    [+&]()      # +^0   (-1 on 2's complement machine)
+    [+<]()      # fail  (reduce is nonsensical)
+    [+>]()      # fail  (reduce is nonsensical)
+    [~&]()      # fail  (sensical but 1's length indeterminate)
+    [~<]()      # fail  (reduce is nonsensical)
+    [~>]()      # fail  (reduce is nonsensical)
+    [+]()       # 0
+    [-]()       # 0
+    [~]()       # ''
+    [+|]()      # 0
+    [+^]()      # 0
+    [~|]()      # ''    (length indeterminate but 0's default)
+    [~^]()      # ''    (length indeterminate but 0's default)
+    [&]()       # all()
+    [|]()       # any()
+    [^]()       # one()
+    [!=]()      # Bool::False   (also for 1 arg)
+    [==]()      # Bool::True    (also for 1 arg)
+    [<]()       # Bool::True    (also for 1 arg)
+    [<=]()      # Bool::True    (also for 1 arg)
+    [>]()       # Bool::True    (also for 1 arg)
+    [>=]()      # Bool::True    (also for 1 arg)
+    [~~]()      # Bool::True    (also for 1 arg)
+    [!~]()      # Bool::False   (also for 1 arg)
+    [eq]()      # Bool::True    (also for 1 arg)
+    [ne]()      # Bool::False   (also for 1 arg)
+    [lt]()      # Bool::True    (also for 1 arg)
+    [le]()      # Bool::True    (also for 1 arg)
+    [gt]()      # Bool::True    (also for 1 arg)
+    [ge]()      # Bool::True    (also for 1 arg)
+    [=:=]()     # Bool::True    (also for 1 arg)
+    [===]()     # Bool::True    (also for 1 arg)
+    [&&]()      # Bool::True
+    [||]()      # Bool::False
+    [^^]()      # Bool::False
+    [//]()      # undef
+    [,]()       # ()
+    [¥]()       # []
+
+User-defined operators may define their own identity values, but
+there is no explicit identity property.  The value is implicit in the
+behavior of the 0-arg reduce, so mathematical code wishing to find
+the identity value for an operation can call C<prefix:{"[$opname]"}()>
+to discover it.
 
-To call some other non-infix function as a reduce operator, you must
+To call some other non-infix function as a reduce operator, you may
 define an alias in infix form.  The infix form will parse the right
 argument as a scalar even if the aliased function would have parsed it
 as a list:
@@ -303,6 +349,8 @@
     &infix:<dehash> ::= postcircumfix:<{ }>;
     $x = [dehash] $a,'foo','bar';  # $a<foo><bar>, not $a<foo bar>
 
+Alternately, just define your own C<< prefix:<[dehash]> >> routine.
+
 Note that, because a reduce is a list operator, the argument list is
 evaluated in list context.  Therefore the following would be incorrect:
 
@@ -318,9 +366,6 @@
     @args = (\%a,'foo','bar');
     $x = [dehash] @args;
 
-Note also that C<[.foo]> always means C<[$_.foo]>, never a reduce operator.
-Infix operators are not allowed to start with a dot.
-
 =head1 Junctive operators
 
 C<|>, C<&>, and C<^> are no longer bitwise operators (see L</Operator

Reply via email to