我正在研究 clojure 宏,我发现我可以通过函数组合来复制很多宏行为。
线程宏就是一个很好的例子:
(defn add1 [n] (+ n 1))
(defn mult10 [n] (* n 10))
(defn threadline [arg]
(-> arg
add1
mult10))
我可以使用管道等高阶函数轻松复制这一点:
(defn pipe [& fns]
(reduce (fn [f g] (fn [arg] (g(f arg)))) fns))
(def pipeline
(pipe
#(+ % 1)
#(* % 10)))
一定存在宏不能被函数替换的情况。我想知道是否有人对此类情况以及所涉及的重复出现的主题有一些很好的例子。
最佳答案
宏的一个重要优点是它们能够在编译时转换代码,而无需评估任何代码。宏在编译期间接收代码作为数据,但函数在运行时接收值。宏允许您在某种意义上扩展编译器。
例如,Clojure 的 and
和 or
被实现为扩展为嵌套 if
形式的递归宏。这允许对 and
/or
的内部形式进行惰性评估,即如果第一个 or
形式为真,则将返回其值,并且不返回任何值的其他人将被评估。如果您将 and
/or
编写为函数,则在检查其所有参数之前都会对其进行求值。
短路控制流在 pipe
函数示例中不是问题,但与 ->
相比,pipe
增加了相当大的运行时复杂性code> 简单地展开为嵌套形式。尝试将其实现为函数的更有趣的宏可能是 some->
。
I'm finding that a lot of macro behavior I can just replicate with function composition
如果您的函数适合它,您当然可以用 comp
来替换带有函数组合的简单线程宏,类似于其他函数式语言中的“point free”风格:#(-> % inc str)
在功能上等同于 (comp str inc)
和 #(str (inc %))
。
通常建议尽可能选择函数,即使在编写宏时,您通常也可以将大部分“工作”外包给函数。
关于Clojure 宏 : When can a function not duplicate a macro's behaviour?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/50779972/