[alexandria-devel] Adding ignorability to once-only
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)) ,@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
participants (1)
-
John Fremlin