如果我跑
(defn c [a b]
(-> a
b))
(c (+ 1 2 3)
(partial * 4))
它会返回(* 4 (+ 1 2 3))
24
假设我想调用c
而不使用第二个s表达式的部分,即
(c (+ 1 2 3)
(* 4))
并获得相同的结果24
。
(defn c...)
会是什么样的?
答案 0 :(得分:2)
你想要的是macro,它是一个接受代码并返回代码的函数。例如,您需要此代码
(c (+ 1 2 3)
(* 4))
等同于此代码:
(-> (+ 1 2 3)
(* 4))
您可以使用Clojure的syntax quote编写c
宏,如下所示:
(defmacro c [a b]
`(-> ~a ~b))
然后,您可以使用macroexpand-1
函数测试您的宏:
(macroexpand-1
'(c (+ 1 2 3)
(* 4)))
;;=> (clojure.core/-> (+ 1 2 3) (* 4))
成功!
(c (+ 1 2 3)
(* 4))
;;=> 24
答案 1 :(得分:1)
在进行函数调用之前,将clojure函数的参数计算为值。如果要传递一个值,该函数在您传递给它的函数内部执行某些操作,那么函数是一个很好的选择值。 始终更喜欢功能的值,以及宏的功能。因为此处的值无效(* 4)
仅评估为4
。
您的第一个示例是获取一个值和一个函数,并使用该值调用该函数。为了更清楚,我可以使用不同的变量名重写该示例:
(defn c' [initial-value function-to-call]
(-> initial-value
function-to-call)
如果我删除线程的第一个宏,它会变得更清晰:
(defn c'' [initial-value function-to-call]
(function-to-call initial-value))
所以我们可以看到第二个参数在用值调用之前需要是一个函数。如果它作为一个尚未编译成函数的s表达式传递,则需要先将其作为一个函数,然后才能使用值运行。
你可以通过几种方式实现这一目标,从最好的方式(在几乎每种情况下几乎可以肯定地做到这一点)订购到更糟糕的情况(这是我从未见过的,因为七年来我一直在以Clojure为生):
->
宏(您可能有理由不这样做,因为您在询问)#(* % 4)
或使用部分我真的提倡选项一,它会做你要求的一切,每个阅读你代码的人都会知道它的作用。
选项二紧随其后,因为阅读它的每个人都会很快弄清楚它的作用。
选项三是非常遥远的第三,因为它意味着你不能将它用于map,reduce等功能,每个人都必须花时间搞清楚它的作用。