Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!cs.utexas.edu!usc!apple!snorkelwacker!bloom-beacon!F.GP.CS.CMU.EDU!Barak.Pearlmutter From: Barak.Pearlmutter@F.GP.CS.CMU.EDU Newsgroups: comp.lang.scheme Subject: Consing Rest Args Considered Harmful Message-ID: Date: 5 Dec 89 23:48:00 GMT Sender: root@athena.mit.edu (Wizard A. Root) Organization: The Internet Lines: 44 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. ]