Search code examples
clojureclojure.spec

Is it possible to resolve a symbol to its value before passing it to macro in Clojure?


Say that I have the following array of keywords

(def keys [::description ::url ::mailing-list])

which I want to reuse in two specs; one for defining a map and one for defining optional arguments to a function.

(require '[clojure.spec :as spec])

(spec/def ::project-map
      (spec/keys :opt-un keys))

(spec/def ::project-args
      (spec/keys* :opt-un keys))

The problem is then that the keys and keys* get passed the quoted symbol 'keys and not the resolved value held in the variable it's referring to.

So my question is: Is it possible to resolve the value of keys at read time like the common lisp #. reader macro, or does the macro have to be redefined to resolve the symbol if it gets a symbol instead of a list literal?


Solution

  • You could also wrap them in another macro, since macros are responsible for how their arguments are evaluated.

    (defmacro def-both [name name* keys]
      `(do (s/def ~name (s/keys :opt-un ~keys))
           (s/def ~name* (s/keys* :opt-un ~keys))))
    
    (user/def-both ::project-map ::project-args [::description ::url ::mailing-list])