Clojure 有没有办法内联传递给宏的函数?
例如,我可以编写如下宏:Clojure 有没有办法内联传递给宏的函数?,clojure,macros,Clojure,Macros,例如,我可以编写如下宏: (defmacro apply-one [f] `(~f 1)) (println (apply-one (fn [x] (+ 42 x)))) ; => 43 但宏扩展会导致额外的函数调用: (macroexpand '(apply-one (fn [x] (+ 42 x)))) ; => ((fn [x] (+ 42 x)) 1) 是否有办法“内联”传递的函数,以便: (macroexpand '(apply-one (fn [x] (+ 42
(defmacro apply-one [f]
`(~f 1))
(println (apply-one (fn [x] (+ 42 x))))
; => 43
但宏扩展会导致额外的函数调用:
(macroexpand '(apply-one (fn [x] (+ 42 x))))
; => ((fn [x] (+ 42 x)) 1)
是否有办法“内联”传递的函数,以便:
(macroexpand '(apply-one (fn [x] (+ 42 x))))
; => (+ 42 1)
我是Clojure的新手,所以下面的解决方案对我来说既恐怖又美丽。但这仍然是一个解决方案
(defmacro apply-one [f]
(eval `(~f 1)))
(println (apply-one (fn [x] `(+ ~x 42))))
; => 43
(pprint (macroexpand-1 '(apply-one (fn [x] `(+ ~x 42)))))
; => (clojure.core/+ 1 42)
关于你实际提出的问题,我会说:不要这样做。内联是JVM做得很好的事情之一,您不应该让代码变得更复杂、可读性更低,以保证某些东西得到内联 你最初的问题陈述,张贴在评论中,有一个更干净的解决方案:不要重复任何东西!不要使用三个几乎相同的子句编写
cond
表达式,而是使用cond
为唯一变化的部分设置变量,然后使用设置的变量无条件地执行正文的其余部分
(let [compute (case command
"turn on" (constantly true)
"turn off" (constantly false)
"toggle" not)]
(doseq [x (range x1 (inc x2))
y (range y1 (inc y2))
:let [i (+ (* y W) x)]]
(aset lights i (compute (aget lights i)))))
你想干什么?可能有更好的方法来实现您的最终目标。@exupero我正在尝试加快宏生成的代码的速度。确切的代码是:,我正试图通过将重复部分提取到分支中来减少
cond
分支中的重复。@exuperodoseq
和aset lights I
之间的所有内容都是完全相同的,避免重复代码会很好。因此,您想到的是函数(fn[I]是的)
、(fn[i]false)
或(fn[i](不是(aget lights i)))
,对吗?@Rulle是的,就像那样。我非常欣赏干净的代码,而且你的版本确实比基于宏的、带有可怕内联的替代版本干净得多。然而,它也慢得多——因为我们一次又一次地调用函数。我知道微基准是非常邪恶的,但在这种情况下,结果似乎是明确的-基于宏的版本在8.6秒工作,你的版本花了282秒。显然,JVM有其局限性。下面是我用来进行基准测试的代码:s/m3/apply one/@cfrick-谢谢!