2

在 clojure 中,我想通过函数列表推送一个画眉值,但我不确定如何以惯用的方式这样做。这个想法是我将有一个包含未知数量的函数的列表,我想利用画眉的可变参数特性。

所以,像这样的事情......

(->> 1 inc inc inc)
; 4

(->> 1 '(inc inc inc))
; does not work, of course
4

4 回答 4

6

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

在可能的情况下,通过宏来处理此类事情

于 2013-01-22T22:31:26.637 回答
5

我认为这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. 这不能用正常的功能组合来完成。

最好在转向宏之前学会充分利用正常的函数组合。对于不习惯的人来说,它们有很多陷阱,应该谨慎使用。

于 2013-01-22T23:04:37.247 回答
2

怎么样:

user=> (def my-fns [inc inc inc])
#'user/my-fns
user=> (->> 1 ((apply comp my-fns)))
4
于 2013-01-23T13:51:45.623 回答
0

我想你可以这样做:

 (defmacro thrush-list [x flist] `(->> ~x ~@flist))
 (thrush-list 1 [inc inc inc])
 ; 4
于 2013-01-22T22:08:30.827 回答