[gambit-list] Newbie: define-macro question

Logan, Patrick D patrick.d.logan at intel.com
Thu Aug 18 12:08:30 EDT 2005


> I'm rather new to Lisp & Scheme (< 3 months total exposure) but I'm
> trying to make a real effort to learn the language. I'm delving into
> macros and having a problem understanding the basics.
>
> I've defined a macro called print-line like so:
> 
> (define-macro (print-line msg)
>    (list `(display ,msg) `(newline)))
>
> When I try to use the macro from the repl I get the error message:
>
> (print-line "hi")
> hi
> ***ERROR in (console)@38.1 -- Operator is not a PROCEDURE

Adam gave a good explanation of this error and how to solve
it. Another issue for a new Scheme programmer is *when* to use a
macro.

In this example there is one argument and generally you would expect
that argument to be evaluated before printing. Simple procedures serve
this purpose just fine, so the preferred solution would be something
like...

(define (print-line msg)
  (display msg)
  (newline))

This may be old news to you, and you're just using print-line as an
example. But I have run into so much code over the years where
programmers chose macros where procedures would be simpler.

I choose to implement a macro primarily when I need to control the
order of evaluation, as in a control structure like if, while, etc.

As an example an old Lisp control structure is called PROG1. This
structure takes a sequence of statements, evaluates each in order, and
returns the result of the first statement after the last has been
evaluated. This is can be expressed as a Gambit macro, but I'll call
it begin1 to be more like Scheme's begin than the old Lisp's progn.

> (define-macro (begin1 first-statement . remaining-statements)
    (let ((result-var (gensym 'first-result)))
      `(let ((,result-var ,first-statement))
         , at remaining-statements
         ,result-var)))
> (begin1 1 2 3)
1
> (begin 1 2 3)
3
> (define result-var 5)
> (begin 1 2 result-var)
5
> (begin result-var 1 2 3)
3
> (begin1 result-var 1 2 3)
5
> (begin1 0 (display result-var) (newline) 1 2 3)
5
0

Then the other nasty thing to watch out for when playing with control
structures is the inadvertent conflict of variables introduced by the
macro and those in the original statements. And so gensym is used to
introduce uniquely named symbols in the macro.

-Patrick




More information about the Gambit-list mailing list