Dylan Design Notes

#37: Variadic Operators (Change)

Version 1, January 1994
Copyright (c) 1993-1994, Apple Computer

The presence of separate binary and variadic versions of some functions 
complicates the Dylan language.  This design note removes several 
variadic operators that are no longer needed in infix Dylan, and renames 
the binary versions of those operators.

-------------------------------------------------------------------

Remove the variadic functions *, +, -, and /.

Rename the generic functions binary*, binary+, binary-, and binary/ to *, 
+, -, and /.

Rename the generic function unary- to negative.

Remove the function unary/.

Remove the variadic functions < and =.

Rename the generic functions binary< and binary= to < and =.

Remove the ability to call <=, >, and >= with more or fewer than two 
arguments.  (/= is already a binary function.)

Remove the variadic functions gcd and lcm.

Rename the generic functions binary-gcd and binary-lcm to gcd and lcm.

Rename the variadic function id? to == and remove the ability to call it 
with more than two arguments.

-------------------------------------------------------------------

Notes

Workarounds for removed constructs:

`+`(x, y, z)                    =>       x + y + z

apply(`+`, stuff)               =>      reduce(`+`, 0, stuff)

unary/(x)                       =>      1 / x

map(`+`, s1, s2, s3)            =>      map(method (x,y,z) 
                                               x + y + z 
                                             end, 
                                            s1, s2, s3);

`<`(x, y, z)                    =>      (x < y) & (y < z) 

	Note: The workaround is less trivial when y is a more complex 
	expression.

logand(x, y, z)                 =>      logand(logand(x, y), z)

apply(logand, stuff)            =>      reduce(logand, -1, stuff)

gcd(x, y, z)                    =>      gcd(gcd(x, y), z)

apply(gcd, stuff)               =>      reduce(gcd, 0, stuff)

apply(lcm, stuff)               =>      reduce(lcm, 1, stuff)

id?(x, y, z)                    =>      (x == y) & (y == z)

apply(`<`, stuff) =>
        
        let (init, limit, next, end?, key, elt)
                = forward-iteration-protocol(stuff);
        if (end?(stuff, init, limit))
          error("at least one argument required.");
        else
          let value = elt(stuff, init);
          let state = next(stuff, init);
          local method loop (value, state)
            if (end?(stuff, state, limit))
              #t;
            else
              let new-value = elt(stuff, state);
              if (value < new-value)
                 loop(new-value, next(stuff, state));
              end if;
            end if;
          end method;
         # assume l-to-r evaluation, else bind temp to first element
         # before potentially clobbering initial state.
         loop(elt(stuff, init), next(stuff, init));
       end if;

apply(id?, stuff) =>

       let (init, limit, next, end?, key, elt)
	              = forward-iteration-protocol(stuff);
       if (end?(stuff, init, limit))
         error("at least two arguments required");
       else
         let value = elt(stuff, init);
         let state = next(stuff, init);
         if (end?(stuff, state, limit))
            error("at least two arguments required");
         else
            local method loop (state)
	             if (value == elt(stuff, state))
	               let nstate = next(stuff, state);
	               end?(stuff, nstate, limit) | loop(nstate);
           	     end if;
	           end method;
            loop(state);
         end if;
       end if;

