I'm trying to write a macro that will define a function exactly once where I don't really care what the name of the function is. My thought was to generate a symbol, use defun
with that, and then put a special property on the symbol. The next time the macro is called, it looks for a symbol with this property first and generates a new symbol if it can't find one.
Here's my code:
(require 'dash)
(require 'cl-lib)
(defun lispdoc-find-handler (key)
(--find (and (functionp it)
(-> (symbol-plist it)
(plist-get 'lispdoc-section-handler)
(eq key)))
(append obarray nil)))
(defmacro lispdoc-defsechandler (key &rest body)
(let ((sym (or (lispdoc-find-handler key) ;; use existing symbol if defined
(cl-gensym))))
`(progn (defun ,sym ,@body)
(put ',sym 'lispdoc-section-handler ,key)
(cons ,key ',sym))))
;; test
(lispdoc-defsechandler :test (examples)
(prin1-to-string examples))
(when-let ((f (lispdoc-find-handler :test)))
(funcall f '(1 2 3 4 5)))
When I eval-defun
my call to lispdoc-defsechandler
, I get a different symbol every time (where I'm very clearly checking to see if it already exists first). When I macroexpand-last-sexp
it, I get the following:
(progn (defun G564 (meta examples)
(prin1-to-string examples))
(put 'G564 'lispdoc-section-handler :test)
(cons :test 'G564))
Evaluating this gives me the same ultimate return value (i.e., (:test . G564)
), but now the macro always gives the same result, too (i.e., the function has actually been defined).
Even if I minimize the macro to just the following
(defmacro lispdoc-defsechandler (key &rest body)
(let ((sym (or (lispdoc-find-handler key)
(cl-gensym))))
`(defun ,sym ,@body)))
I still get the generated sym
as a return value, but its function-value isn't defined. What's going on here? If the function isn't being defined, how is it getting evaluated at all?
print-circle
andprint-gensym
to see the real result of macro expansion.