Explanation of macros; Haskell macros

Peter Seibel peter at javamonkey.com
Mon Nov 3 13:30:11 EST 2003


Joachim Durchholz <joachim.durchholz at web.de> writes:

> Pascal Costanza wrote:

> > This becomes especially useful as soon as your protocols become
> > more sophisticated, and you need to insert instructions at
> > arbitrary places in the code being passed to a macro, or need to
> > control evaluation of the code being passed in some other details.
> 
> Inserting "at arbitrary places" seems rather unmodular to me.
> Either the macro would have to know about the code that it's being
> used in, so that it can identify the places where to insert the code.
> Or the code using the macro will have to pass information to the macro
> -
> which, in a HOF context, means that the code using the HOF approach
> will have to pass the code for "before the insertion point" and "after
> the insertion point" as separate parameters, and the HOF would do the
> necessary linkage between the two codes.
> I'm not sure that macros offer a significant gain here.

So here's one sort of trivial example of something that demonstrates
one aspect of what Pascall was talking about. I'm not sure how you do
this with HOFs since they don't give you any ability to get at the
code at compile time.

  (defmacro show (form)
    "Trace the evaluation of a form and return its value.
  (Could be made smarter about multiple values.)"
    (let ((form-value (gensym)))
      `(let ((,form-value ,form))
         (format *trace-output* "TRACE>> Evaluating ~s; got ~a~%" ',form ,form-value)
         ,form-value)))

  CL-USER: (show (+ 1 2))
  TRACE>> Evaluating (+ 1 2); got 3
  3
  CL-USER: (defun foo (x) (+ (show (+ 1 x)) (+ 3 4) (show (* 5 (* x 4)))))
  FOO
  CL-USER: (foo 10)
  TRACE>> Evaluating (+ 1 X); got 11
  TRACE>> Evaluating (* 5 (* X 4)); got 200
  218

Now that's pretty trivial. But now we can use SHOW to build something
a bit more complex:

  (defmacro show-calls-to ((&rest names) &body body)
    `(progn
       ,@(loop for form in body
             when (member (first form) names) collect `(show ,form)
             else collect form)))

This macro takes a lis of function names to SHOW and a body of forms.
All the top level forms in the body that contain calls to the named
functions are wrapped in a call to SHOW. A more sophisticated, and
useful, version of this macro would use code walker to find
interesting calls other than at the top level.

  CL-USER: (show-calls-to () (- 3 4) (+ 4 5) (* 6 7))
  42
  CL-USER: (show-calls-to (+) (- 3 4) (+ 4 5) (* 6 7))
  TRACE>> Evaluating (+ 4 5); got 9
  42
  CL-USER: (show-calls-to (+ *) (- 3 4) (+ 4 5) (* 6 7))
  TRACE>> Evaluating (+ 4 5); got 9
  TRACE>> Evaluating (* 6 7); got 42
  42

This is not necessarily a typical use of macros, but it does perhaps
demonstrate how a macro can manipulate the code in its arguments
without any particular "cooperation" from the code being manipulated.

-Peter

-- 
Peter Seibel                                      peter at javamonkey.com

         Lisp is the red pill. -- John Fraser, comp.lang.lisp




More information about the Python-list mailing list