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

Two little suggestions for macroexpansion

Several times in the COMMON LISP discussions, individuals have
proffered a "functional" format to alleviate having lots of
keywords for simple operations: E.g. GLS's suggestion on page 137
of "Decisions on the First Draft Common Lisp Manual", which would
allow one to write
  ((fposition #'equal x) s 0 7)  for  (position x s 0 7)
  ((fposition #'eq x) s 0 7)     for  (posq x s 0 7)

This format looks similar to something I've wanted for a long time
when macroexpanding, namely, for a form
	foo = ((<something> . . .) a1 a2)
then, provided that <something> isn't one of the special words for this
context [like LAMBDA or (shudder!) LABEL] why not first expand
(<something> . . .), yielding say <more>, and then try again on the form
(<more> a1 a1).    Of course, (<something> . . .) may not indicate any
macros, and <more> will just be eq to it.   The MacLISP function MACROEXPAND
does do this, but EVAL doesn't call it in this circumstance (rather EVAL does
a recursive sub-evaluation)

     In the context of ((<something> . . .) a1 a2),  have EVAL macroexpand
 the part (<something> . . .) before recursively evaluating it.

  This will have the incompatible effect that
    (defmacro foo () 'LIST)
    ((foo) 1 2)
  no longer causes an error (unbound variable for LIST), but will rather
  first expand into (list 1 2), which then evaluates to (1 2).
  Similarly, the sequence
    (defun foo () 'LIST)
    ((foo) 1 2)
  would now, incompatibly, result in an error.
  [Yes, I'd like to see COMMON LISP flush the aforesaid recursive evaluation,
   but that's another kettle of worms we don't need to worry about now.]

    Let FMACRO have special significance for macroexpansion in the context
 ((FMACRO . <fun>) . . .), such that this form is a macro call which is
 expanded by calling <fun> on the whole form.

As a result of these two changes, many of the "functional programming
style" examples could easily be implemented by macros.  E.g.
  (defmacro FPOSITION (predfun arg)
		 `(SI:POS-HACKER ,',arg
				 ,@(cdr form)
where SI:POS-HACKER is a version of POSITION which accepts keyword arguments
to direct the actions, at the right end of the argument list.
Notice how

    ((fposition #'equal x) a1 a2)
    ((fmacro . (lambda (form)
		  `(SI:POS-HACKER X ,@(cdr form) ':PREDICATE #'EQUAL)))

If any macroexpansion "cache'ing" is going on, then the original form
((fposition #'equal x) a1 a2)  will be paired with the final
result (SI:POS-HACKER X A1 A2 ':PREDICATE PREDFUN) -- e.g., either
by DISPLACEing, or by hashtable'ing such as MACROMEMO in PDP10 MacLISP.

Now unfortunately, this suggestion doesn't completely subsume the
functional programming style, for it doesn't directly help with the
case mentioned by GLS:
  ((fposition (fnot #'numberp)) s)  for (pos-if-not #'numberp s)
Nor does it provide an easy way to use MAPCAR etc, since
  (MAPCAR (fposition #'equal x) ...)
doesn't have (fposition #'equal x) in the proper context.
[Foo, why not use DOLIST or LOOP anyway?]   Nevertheless, I've had many
ocasions where I wanted such a facility, especially when worrying about
speed of compiled code.

Any coments?