[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Consing Rest Args Considered Harmful



In Oaklisp, Kevin and I used a somewhat ideosyncratic solution to the
rest args problem.  A form like (lambda (a b . c) BODY) makes a
procedure of at least two arguments, and BODY can refer to the first
two, A and B.  But the token C is not a variable; it is special syntax
indicating that an indeterminite number of rest arguments are being
passed.  Since it is just syntax, it can't be closed over.  It can be
used in only one context: in a tail recursive call that gets you out of
BODY, you must terminate the call with ". C".  And all exits from body
must be tail recursive, and must do this.  For instance, you could write

 (define (foo a b . c)
    (list a 'aye b 'bee . c))

There is a way to find out how many extra arguments were passed, as in
the following form.  REST-LENGTH is syntax though, not a procedure.  I'm
still not sure if this was a good idea, although it is simple enough to
provide.

 (define (foo a b . c)
    (if (> (rest-length c) 5)
        (list 'lots 'of . c)
        (list 'little . c)))

A number of utility functions are provided for manipulating the rest
arguments.  For instance, LISTIFY-ARGS takes at least one argument, a
procedure, which it calls on a list made up of any additional arguments.
So to write a function which takes an arbitrary number of arguments and
returns its second, you could write

  (define (second-arg a x . rest)
     (listify-args (lambda (l) x) . rest))

Other functions useful for rest argument consumption are also provided.

We felt that this mechanism provided the bare minimum of functionality
necessary in the base level language to work with rest arguments,
without imposing undue implementation constraints.  In using it, we
found that almost all uses of rest arguments fit naturally into the
paradigm, and very rarely is there any reason to listify the rest
arguments.  In particular, this is true of things like + and * which can
basically eat there arguments left to right until they're all gone.

[ In passing, I should mention that the compatibility package makes
  dotted rest args behave in the usual ugly but standard way. ]