Clojure 定义一个将两个s表达式串在一起的函数
如果我跑Clojure 定义一个将两个s表达式串在一起的函数,clojure,functional-programming,Clojure,Functional Programming,如果我跑 (defn c [a b] (-> a b)) (c (+ 1 2 3) (partial * 4)) 它返回(*4(+1 2 3))的结果,即24 假设我想调用c,而不使用第二个s表达式的partial,即 (c (+ 1 2 3) (* 4)) 并得到相同的结果24 (defn c…)看起来像什么?您需要的是一个函数,它接受代码并返回代码。例如,您需要此代码 (c (+ 1 2 3) (* 4)) 与本规范等效: (-> (+
(defn c [a b]
(-> a
b))
(c (+ 1 2 3)
(partial * 4))
它返回(*4(+1 2 3))
的结果,即24
假设我想调用c
,而不使用第二个s表达式的partial,即
(c (+ 1 2 3)
(* 4))
并得到相同的结果24
(defn c…)
看起来像什么?您需要的是一个函数,它接受代码并返回代码。例如,您需要此代码
(c (+ 1 2 3)
(* 4))
与本规范等效:
(-> (+ 1 2 3)
(* 4))
您可以使用Clojure编写c
宏,如下所示:
(defmacro c [a b]
`(-> ~a ~b))
然后,您可以使用以下函数测试宏:
(macroexpand-1
'(c (+ 1 2 3)
(* 4)))
;;=> (clojure.core/-> (+ 1 2 3) (* 4))
成功
(c (+ 1 2 3)
(* 4))
;;=> 24
在进行函数调用之前,clojure函数的参数将被计算为值。如果您希望传入一个值,该值在您要传递给它的函数中起作用,那么函数是一个很好的选择始终将值优先于函数,将函数优先于宏。因为一个值在这里没有用处,
(*4)
的计算结果只是4
第一个示例是取一个值和一个函数,并用该值调用该函数。为了更清楚地说明这一点,我可以用不同的变量名重写该示例:
(defn c' [initial-value function-to-call]
(-> initial-value
function-to-call)
如果我删除thread first宏,它会变得更清晰:
(defn c'' [initial-value function-to-call]
(function-to-call initial-value))
所以我们可以看到,第二个参数必须是一个函数,才能用值调用它。如果它作为尚未编译成函数的s表达式传递,则需要先将其编译成函数,然后才能使用值运行
你可以通过几种方式来实现这一点,从最好的(几乎可以肯定你在任何情况下都应该这样做)到非常糟糕的(我从来没有看到过有理由在七年的时间里以写Clojure为生):
->
宏(您可能有理由不这样做,因为您提出了要求)#(*%4)
,或者像现在一样使用partial选项三是非常遥远的第三个选项,因为它意味着你不能将它与map、reduce等函数一起使用,每个人都必须花时间弄清楚它的功能。它需要看起来像一个宏。非常感谢Sam。我想知道我最后何时才能开始编写宏…@monch1962好吧,在这种特殊情况下,您仍然不需要编写任何宏,因为这里的
c
只提供了->
功能的一个子集。您不太可能真正需要在这里使用宏。“或者至少你应该先努力找到另一条路。”阿瑟鲁费尔德同意。当你需要宏时,宏是很棒的,但这比你想象的要少;尽可能避免编写宏。请不要让宏成为调用函数的唯一方式,我写clojure的时间越长,每年编写的宏就越少(ps:2016年为零)