通过 Clojure 中的变量将数据传递给宏(脚本)

Pass data to macro via variable in Clojure(Script)

有什么技巧可以在不直接传递数据或不使用 eval 的情况下完成这项工作吗?

(defmacro pair-defs [data]
  (cons 'do
    (for [[k v] data]
      `(def ~k ~v))))

(def data '((a 1) (b 2) (c 3)))
(pair-defs data)

如果您的 data 变量在宏调用之前在命名空间中定义,您可以使用一些命名空间操作函数来按名称解析它的值:

(defmacro pair-defs [data]
  `(do ~@(for [[k v] @(ns-resolve *ns* data)]
           `(def ~k ~v))))

user> (def data [['a 10] ['b 20]])
#'user/data

user> (pair-defs data)
#'user/b

或者同时处理文字数据和变量名数据:

(defmacro pair-defs [data]
  (let [dt (if (symbol? data) @(ns-resolve *ns* data) data)]
    `(do ~@(for [[k v] dt]
             `(def ~k ~v)))))

调用被扩展为所需的形式:(do (def a 10) (def b 20))

因此,不用像 eval 这样的肮脏技巧来解析命名空间 val 是完全可能的,但我发现它是一种完全不需要的宏用法。例如,您的任务很容易被简单的函数调用替换。

(defn pair-defs1 [data]
  (doseq [[k v] data]
    (intern *ns* k v)))

它适用于任何 data 序列,无论是本地的还是全局的,文字的还是生成的