Piping data through arbitrary functions in Clojure

白昼怎懂夜的黑 提交于 2019-12-30 07:58:09

问题


I know that the -> form can be used to pass the results of one function result to another:

(f1 (f2 (f3 x))) 
(-> x f3 f2 f1) ; equivalent to the line above

(taken from the excellent Clojure tutorial at ociweb)

However this form requires that you know the functions you want to use at design time. I'd like to do the same thing, but at run time with a list of arbitrary functions.

I've written this looping function that does it, but I have a feeling there's a better way:

(defn pipe [initialData, functions]
  (loop [
      frontFunc (first functions)
      restFuncs (rest functions)
      data initialData ]
    (if frontFunc
      (recur (first restFuncs) (rest restFuncs) (frontFunc data) )
      data )
  ) )

What's the best way to go about this?


回答1:


I must admit I'm really new to clojure and I might be missing the point here completely, but can't this just be done using comp and apply?

user> (defn fn1 [x] (+ 2 x))
user> (defn fn2 [x] (/ x 3))
user> (defn fn3 [x] (* 1.2 x))
user> (defn pipe [initial-data my-functions] ((apply comp my-functions) initial-data))
user> (pipe 2 [fn1 fn2 fn3])
2.8



回答2:


You can do this with a plain old reduce:

(defn pipe [x fs] (reduce (fn [acc f] (f acc)) x fs))

That can be shortened to:

(defn pipe [x fs] (reduce #(%2 %1) x fs))

Used like this:

user> (pipe [1 2 3] [#(conj % 77) rest reverse (partial map inc) vec])
[78 4 3]



回答3:


If functions is a sequence of functions, you can reduce it using comp to get a composed function. At a REPL:

user> (def functions (list #(* % 5) #(+ % 1) #(/ % 3)))
#'user/my-list
user> ((reduce comp functions) 9)
20

apply also works in this case because comp takes a variable number of arguments:

user> (def functions (list #(* % 5) #(+ % 1) #(/ % 3)))
#'user/my-list
user> ((apply comp functions) 9)
20


来源:https://stackoverflow.com/questions/3683219/piping-data-through-arbitrary-functions-in-clojure

标签
易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!