Subject: &optional and &key in Scheme [was: Re: LISP for embedded systems ]
From: rpw3@rigden.engr.sgi.com (Rob Warnock)
Date: 1999/10/25
Newsgroups: comp.lang.lisp
Message-ID: <7v0f4u$7rj7p@fido.engr.sgi.com>
Christopher R. Barry <cbarry@2xtreme.net> wrote:
+---------------
| Tim Bradshaw <tfb@tfeb.org> writes:
| > Are you aware how scheme does optional arguments?  I guess not.
| 
| I know how scheme does &rest arguments:
|   ((lambda (x . y) (list x y)) 1 2 3 4 5)  =>  (1 (2 3 4 5))
| I don't know how to do &optional or &key ones, however. Do enlighten me.
+---------------

You can of course "do" &optional and &key (or rather, provide somewhat
similar functionality) with explicit post-processing of the &rest argument
in your function. [Note: In Scheme, most people use simple symbols with
no colon prefix as "keywords", though MzScheme provides an explicit
"keyword" datatype that may be helpful.] This is made much more readable
(but certainly no faster) by using convenience routines, so that you could
write the CL function:

	(defun foo (a b c &key d (e 123) (f 456 f-p))
	  ... )

in Scheme like this, maybe:

	(define (foo a b c . rest)
	  (let ((d (key-value rest 'd))
		(e (key-value rest 'e 123))
		(f (key-value rest 'f 456))
		(f-p (key-present? rest 'f)))
	    ... ))

Or assuming you had non-hygenic macros available (such as "defmacro",
which most Schemes either have or can craft up out of whatever low-level
macros they *do* have), you might decide that by convention your macro
would capture the variable name "rest", and write something like this:

	(define (foo a b c . rest)
	  (with-parsed-keys (d (e 123) (f 456 f-p))
	    ... ))

As far as &optional goes, if you use explicit parsing you usually
have to manually supply an index, e.g., from some actual code I wrote
a long time ago (before I knew that CL called them &optional, or I
might have called the helper function "opt-value" instead of "dlft")

	(define (dump . rest)		; &optional addr size
	  (let* ((addr (dflt rest 0 dump-prev-addr))
		 (size (dflt rest 1 dump-prev-size))
		 (j (modulo addr 16)))
	    ...))

Or, as above, with macro support:

	(define (dump . rest)		; &optional addr size
	  (with-parsed-optionals ((addr dump-prev-addr)
				  (size dump-prev-size))
	    ... ))

[Or even knock yourself out and write a "defun" macro that does it all
for you automatically...]  ;-}  ;-}

Yes, it's ugly. Yes, CL does it better, and it's all IN THE STANDARD!
But also, yes, with a little macrology[*] one can approximate the
convenience even in Scheme.


-Rob

[*] And SIOD *does* have just enough of a macro facility to enable
defining "defmacro", and hence be able to write in the above style.

And with a bunch of work (once), you can even use SIOD's macros to
get (almost) all of the R4RS syntax.

-----
Rob Warnock, 8L-846		rpw3@sgi.com
Applied Networking		http://reality.sgi.com/rpw3/
Silicon Graphics, Inc.		Phone: 650-933-1673
1600 Amphitheatre Pkwy.		FAX: 650-933-0511
Mountain View, CA  94043	PP-ASEL-IA