[alexandria-devel] Adding ignorability to once-only
John Fremlin
john at fremlin.org
Sun May 24 10:58:38 UTC 2009
Dear Alexandrians,
Thanks for your great library. However, consider this (on SBCL)
CL-USER> (macrolet ((m (x) (alexandria:once-only (x) (declare (ignore x)) t))) (m t))
; in: LAMBDA NIL
; (LET ((#:X871 T))
; T)
;
; caught STYLE-WARNING:
; The variable #:X871 is defined but never used.
;
; compilation unit finished
; caught 1 STYLE-WARNING condition
T
CL-USER> (macrolet ((m (x) (alexandria:once-only (x) `(locally (declare (ignorable ,x)) t)))) (m t))
; in: LAMBDA NIL
; (LOCALLY (DECLARE (IGNORABLE #:X830)) T)
;
; caught STYLE-WARNING:
; declaring unknown variable #:X830 to be ignored
; (LET ((#:X830 T))
; (LOCALLY (DECLARE (IGNORABLE #:X830)) T))
;
; caught STYLE-WARNING:
; The variable #:X830 is defined but never used.
In complex macros sometimes it's nice to be able to declare a once-only
variable ignorable.
I've been using this version in my fast Lisp webserver.
http://github.com/vii/teepeedee2/tree/master
(defun force-first (x) (if (listp x) (first x) x))
(defun force-rest (x) (when (listp x) (rest x)))
(defmacro once-only ((&rest names-and-decls) &body body)
;; Each name is already lexically bound to something in the macro M using once-only
;; For each NAME:
;; - Generate a unique symbol SYM with value a unique symbol SYM-VAL
;; - In the macro-expansion of M, bind SYM-VAL to the value of NAME
;; - For BODY, bind NAME to SYM
;; It is necessary to use the indirection SYM -> SYM-VAL so that a
;; new symbol will be created for each invocation of M, not just
;; for each invocation of once-only
(let* ((names (mapcar 'force-first names-and-decls))
(declarations (mapcar 'force-rest names-and-decls))
(symbols (loop for name in names collect (gensym (string name)))))
`(let ,(loop for symbol in symbols
for name in names
collect `(,symbol (gensym ,(string name))))
`(let ,(list ,@(loop for name in names
for symbol in symbols
collect `(list ,symbol ,name)))
,@(list
,@(loop for symbol in symbols for decl in declarations
append
(loop for d in decl
collect ``(declare (,@,(if (listp d) d `(list `,',d)) ,,symbol)))))
,(let ,(loop for symbol in symbols
for name in names
collect `(,name ,symbol))
, at body)))))
I wrote this macro when I was quite unfamiliar with Lisp. I'm sure you
can think a better syntax and can improve it.
The result is syntax like this
CL-USER> (macrolet ((m (x) (once-only ((x ignorable)) (declare (ignore x)) t))) (m t))
T
More information about the alexandria-devel
mailing list