在Clojure中,如何通过一系列功能来打动?

In clojure, how does one thrush through a list of functions?

在Clojure中,我想通过一个函数列表来推送一个画眉值,但是我不确定如何以惯用的方式这样做。我的想法是,我将拥有一个包含未知数量功能的列表,并且我想利用鹅口疮的各种特性。

所以,这样的事情...

1
2
3
4
5
(->> 1 inc inc inc)
; 4

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

reduce在这种情况下可以很好地做到这一点

1
2
3
4
5
6
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)表示法。

1
2
=> ((comp inc inc inc) 1)
4

如果函数通常使用可变参数,但您希望将其作为集合,则将其与惯用的apply组合。

1
2
=> ((apply comp (repeat 3 inc)) 1)
4

请注意,尽管它从右向左滚动

1
2
3
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的答案是完全可以接受的,并且是简化和功能编程的一个很好的例子。不过,按原样使用它可能会妨碍您熟悉s表达式的"简单性"。.

请注意宏的!

->和->>是宏的原因是它们积极地重写形式,因此您可以在范围内使用通常不完整的参数表示法,例如(filter odd?),而不必求助于过度使用partial。使用正常的功能堆肥无法做到这一点。

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


怎么样:

1
2
3
4
user=> (def my-fns [inc inc inc])
#'user/my-fns
user=> (->> 1 ((apply comp my-fns)))
4

我想你可以这样做:

1
2
3
 (defmacro thrush-list [x flist] `(->> ~x ~@flist))
 (thrush-list 1 [inc inc inc])
 ; 4