[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Using Macros in Lisp
- To: info-macl@cambridge.apple.com
- Subject: Using Macros in Lisp
- From: Tom McDougal <mcdougal@gargoyle.uchicago.edu>
- Date: Wed, 6 Mar 91 08:27:06 CST
Luke Hohmann writes:
>
> I am trying to use macros in a very large program to
> a. reduce the size of the source code,
> b. make the source code easier to read,
> c. Be a really cool lisp programmer.
My impression is that, according to conventional wisdom, macros
are to be avoided wherever function calls will do, because they:
a. are hard to write,
b. make the source code harder to read,
c. make the program *much* harder to debug.
Conventional wisdom or not, I know (a) and (c) are true! I do
use a few macros, however, and you have to understand macros to
write "defsetf" forms.
I do use them, however. Here are two that I use:
; INSIST written by Christopher Reisbeck, *slightly* modified
; by Tom McDougal.
; A nice little anti-bugging tool for argument-checking.
; Syntax:
; (insist <where> -tests- )
; Example of use:
; (defun invert (x)
; (insist foo (numberp x) (not (zerop x)))
; (/ x))
; If any of the -tests- fails at run-time, an error message
; is printed identifying the place (<where>) and the test
; that failed. E.g.
; > (foo 0)
; Error: (not (zerop x)) failed in foo.
;
; INSIST expands into a large COND.
(defmacro insist (where &rest tests)
`(cond ,@(make-insist-forms where tests)))
; make-insist-forms returns a list of COND clauses. I recommend
; trying it out independently to get a feel for what is going on.
; E.g. (make-insist-forms 'foo '((numberp x) (not (zerop x))))
(defun make-insist-forms (where tests)
(cond ((null tests) '())
(t (cons `((not ,(car tests))
(error "~s failed in ~s"
,(car tests) ,where))
(make-insist-forms where (cdr tests))))))
;;;----------------
; Example 2: Most of us around here are former T hackers, so we
; like the following:
; ITERATE from T. The version I saw was written by Jim Firby, but
; Slade probably did it first.
; How many times do you want to march down a list until you
; find something? How many times do you find yourself writing
; a little auxilliary recursive function?
; Syntax:
; (iterate <name> <args-w/-initial-bindings>
; -body-)
; Example:
; (defun fact (x)
; (iterate fact-aux ((a x) (result 1))
; (if (zerop a)
; result
; (fact-aux (1- a) (* result a)))))
;
; This macro expands into a LABELS construct.
(defmacro iterate (name bindings &body body)
`(labels ((name ,(mapcar #'car bindings)
,@body))
,(cons name (mapcar #'cadr bindings))))
; So, FACT expands into:
; (defun fact (x)
; (labels ((fact-aux (a result)
; (if (zerop a)
; result
; (fact-aux (1- a) (* result a)))))
; (fact-aux x 1)))
; Hope this helps!
--Tom (mcdougal@cs.uchicago.edu)
2025, Edgar Spindizzy realizes that
his time machine works.