Subject: Re: Special forms vs. Macros
From: rpw3@rpw3.org (Rob Warnock)
Date: Fri, 07 Jan 2005 02:15:31 -0600
Newsgroups: comp.lang.lisp
Message-ID: <HoOdnRFxfrS-2EPcRVn-pQ@speakeasy.net>
Adrian Kubala  <adrian@sixfingeredman.net> wrote:
+---------------
| Macros DO let you implement your own evaluation rules, but only by
| virtue of the underlying special forms. If macros could only expand to
| function applications, then they would not be able to do this. So that's
| why you can implement if as a macro in terms of cond, or visa versa, but
| you can't implement either without some lower-level special form. At the
| very least, lambda must be a special form, musn't it?
+---------------

LAMBDA and QUOTE, I think, and in Common Lisp, probably FUNCTION as well.
And LOAD-TIME-VALUE, for nice compilation.

Of course, you need primitve *functions* such as FUNCALL & APPLY & C[AD]*R
and arithmetic and so forth, but I think the above list are the minimum
of special forms. You also need functional forms for "setters" for all
the common data types that don't already have them, e.g. AREF! (to use
the Scheme convention), which in CMUCL is LISP::%ASET and in CLISP is
SYSTEM::STORE.

You can even do away with IF (or COND) if you have a primitive function,
say, TRUTH-NUMBER, that takes a Lisp value and returns the fixnum 0 for
true and 1 for false [or vice-versa, it doesn't matter, either can be
made to work] and arrays and accessors [as above], like so:

	(defmacro if (boolean consequent alternate)
	  `(funcall (aref (load-time-value
			    (make-array 2 :initial-contents
			                  (list (lambda () ,consequent)
					        (lambda () ,alternate)))))
		    (truth-number ,boolean)))

[Note: The LOAD-TIME-VALUE isn't cheating, only an efficiency hack.
You can do the same thing without it, though with a lot more consing...]

Hmmm... Though looking back at the discussion we has about this a
year ago, it looks like there are a *LOT* more mandatory special
forms in Common Lisp than in Scheme:

    block      let*                  return-from      
    catch      load-time-value       setq             
    eval-when  locally               symbol-macrolet  
    flet       macrolet              tagbody          
    function   multiple-value-call   the              
    go         multiple-value-prog1  throw            
    if         progn                 unwind-protect   
    labels     progv                                  
    let        quote

PROGN, LET, LET*, and FLET (maybe) can be hacked with FUNCALL & LAMBDA.
Even LABELS can be hacked with the Y operator (ugh!). SETQ can be hacked
with an appropriate set of macros and low-level setters.

But BLOCK, TAGBODY, GO, UNWIND-PROTECT, MULTIPLE-VALUE-CALL, RETURN,
RETURN-FROM, etc., I dunno. I think you're in trouble there. And you
*can't* do EVAL-WHEN in a macro, can you? And then all the declaration
stuff -- DECLAIM, DECLARE, LOCALLY, THE -- those are pretty "special"
operators.


-Rob

-----
Rob Warnock			<rpw3@rpw3.org>
627 26th Avenue			<URL:http://rpw3.org/>
San Mateo, CA 94403		(650)572-2607