【问题标题】:Clojure macros : Executing code inside macrosClojure 宏:在宏中执行代码
【发布时间】:2015-04-20 13:11:33
【问题描述】:

我想创建一个宏,以便我可以在变量本身内添加变量名。我有这个Unit 记录。它的name 成员存储了将要​​创建的变量的名称。 即像(def a-variable (->Unit 1 1 "a-varible")) 但我不想自己传递变量名。

而且我认为宏可以派上用场。 :)

代码如下:

(defrecord Unit 
    [value gradient name]
  Object
  (toString [_]
    (str name " : ")))


(defmacro create-unit1 [var-name & body]
  `(def ~var-name ~(concat body (list (name var-name)))))

(defmacro create-unit2 [var-name & body]
  `(def ~var-name (concat ~@body (list (name '~var-name)))))

但他们都没有给我写代码:

neurals.core> (macroexpand '(create-unit1 a (->Unit 1.0 0.0)))
(def a ((->Unit 1.0 0.0) "a"))

neurals.core> (macroexpand '(create-unit2 a (->Unit 1.0 0.0)))
(def a (clojure.core/concat 
       (->Unit 1.0 0.0) (clojure.core/list 
                           (clojure.core/name (quote a)))))
neurals.core> 

我想要:

(def a (->Unit 1.0 0.0 (clojure.core/name (quote a))))

在宏内执行concat的正确方法是什么?

【问题讨论】:

    标签: clojure macros


    【解决方案1】:

    您可以通过删除create-unit1 中的& 来修复您的代码:

    (defmacro create-unit1 [var-name body]
      `(def ~var-name ~(concat body (list (name var-name)))))
    
    (macroexpand `(create-unit1 a (->Unit 1.0 1.0)))
    ;; => (def user/a (user/->Unit 1.0 1.0 "a"))
    

    您还可以添加一点语法糖:

    (defmacro create-unit1 [var-name body]
      `(def ~var-name (~@body ~(name var-name))))
    

    或者,为了让所有这些更惯用:

    (defmacro defunit [sym value gradient]
      `(def ~sym (->Unit ~value ~gradient ~(name sym))))
    
    (defunit a 1.0 1.0)
    ;; => #user.Unit{:value 1.0, :gradient 1.0, :name "a"}
    

    【讨论】:

    • 哦.. (~@body ~(name var-name)) 是连接它的方式:).. 酷
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-07-22
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多