在 clojure 中,我想通过函数列表推送一个画眉值,但我不确定如何以惯用的方式这样做。这个想法是我将有一个包含未知数量的函数的列表,我想利用画眉的可变参数特性。
所以,像这样的事情......
(->> 1 inc inc inc)
; 4
(->> 1 '(inc inc inc))
; does not work, of course
在 clojure 中,我想通过函数列表推送一个画眉值,但我不确定如何以惯用的方式这样做。这个想法是我将有一个包含未知数量的函数的列表,我想利用画眉的可变参数特性。
所以,像这样的事情......
(->> 1 inc inc inc)
; 4
(->> 1 '(inc inc inc))
; does not work, of course
reduce 在这种情况下做得很好
user> (reduce #(%2 %1) 1 [inc inc inc])
4
user> (defn thrush [val funs] (reduce #(%2 %1) val funs))
#'user/thrush
user> (thrush 1 [inc inc inc dec])
3
在可能的情况下,通过宏来处理此类事情
我认为这comp
是这里最惯用的选项,尽管它会使用前缀语法。这也更符合正常的 Clojure (fn args) 表示法。
=> ((comp inc inc inc) 1)
4
apply
如果函数通常采用可变参数,但您想为其提供一个集合,请将其与惯用语结合起来。
=> ((apply comp (repeat 3 inc)) 1)
4
请注意,尽管它是从右到左的
=> ((comp str inc inc inc) 1)
"4"
=> ((comp inc inc inc str ) 1)
ClassCastException java.lang.String cannot be cast to java.lang.Number
这也更符合 Clojure/Lisp s 表达式。
如果您想要更“简单”的人类可读符号,Arthur Ulfeldt 的答案是完全可以接受的,并且是 reduce 和函数式编程的一个很好的例子。不过,“按原样”使用它可能会妨碍熟悉 s 表达式的“简单性”。
小心宏!
-> 和 ->> 是宏的原因是它们主动重写表单,因此您可以(filter odd?)
在它们的范围内使用通常不完整的参数表示法,而不必过度使用partial
. 这不能用正常的功能组合来完成。
最好在转向宏之前学会充分利用正常的函数组合。对于不习惯的人来说,它们有很多陷阱,应该谨慎使用。
怎么样:
user=> (def my-fns [inc inc inc])
#'user/my-fns
user=> (->> 1 ((apply comp my-fns)))
4
我想你可以这样做:
(defmacro thrush-list [x flist] `(->> ~x ~@flist))
(thrush-list 1 [inc inc inc])
; 4