A problem with many macros in lisp is that most other language already have similar things in their standard. The more general approach with lisp isnt understood by many people. "Why should we use macros for defining cond, we already have a switch-instruction", etc.
Some really small macros I wrote - of which i am sure most common language do not have - were macros to translate coordinates when Drawing. I.e. i defined two variables *translation-x* and *translation-y* and all my draw-instructions were relatively to this. Sometimes I needed to change these values temporarily. So I wrote the macros. I also had one type with slots x and y, as it sometimes was easier to handle coordinates this way, but sometimes i just wanted to write them down explicitly.
- Code: Select all
(defmacro with-translation-* ((x y) &body body)
`(let ((*current-translation-x* (+ ,x *current-translation-x*))
(*current-translation-y* (+ ,y *current-translation-y*)))
,@body))
(defmacro with-translation ((translation) &body body)
`(with-translation-* ((x ,translation) (y ,translation)) ,@body))
(defmacro with-negative-translation-* ((x y) &body body)
`(with-translation-* ((- ,x) (- ,y)) ,@body))
(defmacro with-negative-translation ((translation) &body body)
`(with-negative-translation-* ((x ,translation) (y ,translation)) ,@body))
This is nothing special, nothing exciting, nothing new. You dont really need it, you could always set the translation explicitly, or pass an object with the current relative zero-point to every drawing-function. It is just useful. One can argue about it, but to me, it makes the code look better.
Another thing is some kind of a let-instruction for accessors. I sometimes had the problem that I temporarily wanted to set some slot of an object to some other value, mostly, calling the accessor directly was needed, since other things depended on that slot. So i defined the following macro, which does exactly this:
- Code: Select all
(defmacro let-accessor (((accessor object) value) &body body)
"Temporarily set an Accessor to another value."
(let ((symbol (gensym)))
`(let ((,symbol (,accessor ,object)))
(unwind-protect
(progn (setf (,accessor ,object) ,value) ,@body)
(setf (,accessor ,object) ,symbol)))))
(defmacro let-accessors ((&rest bindings) &body body)
"Temporarily set Accessors to other values."
(let ((cbind (car bindings)))
(if cbind
`(let-accessor
((,(first (first cbind)) ,(second (first cbind))) ,(second cbind))
(let-accessors (,@(cdr bindings)) ,@body))
`(progn ,@body))))
Again you can argue whether that is good - as it abstracts a lot of function calls into a little code block, which makes the code look more efficient than it is. But again - it is useful, it makes the code more readable.
The readability is a general argument I think. "Programs are written for humans, not for computers"