简体   繁体   English

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

[英]Pass data to macro via variable in Clojure(Script)

Is there any trick to make this work without passing the data directly or using eval? 有没有任何技巧可以在不直接传递数据或使用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)

If your data var is defined in namespace before the macro call,you can use some namespace manipulating functions to resolve it's value by name: 如果在宏调用之前在命名空间中定义了data var,则可以使用一些命名空间操作函数来按名称解析它的值:

(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

or to handle both literal data and data by var name: 或者通过var名称处理文字数据和数据:

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

the call is expanded to the desired form: (do (def a 10) (def b 20)) 呼叫扩展到所需的形式:( (do (def a 10) (def b 20))

So resolving the namespace val without dirty tricks like eval is totally possible, but i find it to be quite an unneeded usage of macros. 所以解决命名空间val没有像eval这样的肮脏技巧是完全可能的,但我发现它是非常不必要的宏用法。 For example your task is easily replaceable by plain function call. 例如,您的任务可以通过普通函数调用轻松替换。

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

it would work on any data sequence, be it local or global, literal or generated 它适用于任何data序列,无论是本地还是全局,文字或生成

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM