你如何避免IF评估宏?

时间:2015-08-05 22:29:52

标签: clojure

如果您运行以下内容,则仅打印“foo”:

[
    { "keys": ["f5"], "command": "build" }
]

但是,如果将宏作为参数传递给if,它似乎会立即评估这两个宏。

(if true (println "foo") (println "bar"))
;foo

如何避免同时运行这两个宏并仅根据真实条件对其进行评估?

编辑:

我混淆的主要原因是这可以在普通的lisp中使用。我不知道lisp多么常见地处理编译宏的方式不同,但我猜测它与JVM上的更多自由度有关。

澄清实际代码是创建某种类型的表单而不引用它们作为参数。代码正在迭代并且将变得更复杂,但在当前状态下是:

(defmacro foo
  []
  (println "foo"))

(defmacro bar
  []
  (println "bar"))

(if true (foo) (bar))
;foo
;bar

我希望在评估if之前不要扩展两个宏,因为将除列表之外的内容传递给bar会导致异常。我现在明白这是不可能的,因为扩展发生在编译时。我已经转而使用多方法 - 这种方法更冗长,但我认为它更具多态性。

3 个答案:

答案 0 :(得分:2)

Alan拥有它的权利(就需要立即修复而言),但要说明理由:

宏在编译时评估,而不是运行时。对于仅在运行时已知的内容来说,控制所编译的内容显然是不可能的,因为所有编译都必须在运行时启动之前完成。

答案 1 :(得分:1)

您忘记了"语法引用"。代码应如下所示:

(defmacro foo
  []
  `(println "foo"))

(defmacro bar
  []
  `(println "bar"))

(if true 
  (foo) 
  (bar))

=> FOO

答案 2 :(得分:0)

宏是语法上的抽象。当您看到经常编写的模式时使用它,但由于参数评估,您无法使用函数。宏评估代码并且不应该有副作用,因为你无法控制何时扩展(运行)。

foobar应该是函数。然后它会像你想象的那样工作。

(defn foo
  []
  (println "foo"))

(defn bar
  []
  (println "bar"))

(if true 
  (foo) 
  (bar)) ; prints "foo"

在不需要宏时使用宏被认为是不好的做法。