在将符号传递给Clojure中的宏之前,是否可以将符号解析为其值?

时间:2017-04-10 11:15:38

标签: clojure clojure.spec

假设我有以下关键字数组

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

我想在两个规格中重复使用;一个用于定义一个映射,另一个用于定义函数的可选参数。

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

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

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

问题是,keyskeys*会传递带引号的符号'keys而不是它所引用的变量中保存的已解析值。

所以我的问题是:是否可以像读取常见的lisp #.读取器宏一样在读取时解析键的值,或者如果宏获取符号,则必须重新定义宏以解析符号列表文字?

3 个答案:

答案 0 :(得分:1)

您可以使用eval

构建一个半危险的解决方案
(spec/def ::project-map
  (eval `(spec/keys :opt-un ~keys)))

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

这是通过对clojurians松弛的建议。

答案 1 :(得分:1)

您也可以将它们包装在另一个宏中,因为宏负责评估它们的参数。

(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])

答案 2 :(得分:0)

或者你可以这样做:

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

可能需要使用合格的命名空间(例如::opt-un

spec/def

已经是一个宏;)