4Clojure Problem 58表述为:
<小时/>编写一个允许您创建函数组合的函数。参数列表应采用可变数量的函数,并创建一个从右到左应用它们的函数。
(= [3 2 1] ((__ rest reverse) [1 2 3 4]))
(= 5 ((__ (partial + 3) second) [1 2 3 4]))
(= true ((__ zero? #(mod % 8) +) 3 5 7 9))
(= "HELLO" ((__ #(.toUpperCase %) #(apply str %) take) 5 "hello world"))
此处的__
应替换为解决方案。
在此问题中,不应使用函数 comp
。
我找到的解决方案是:
(fn [& xs]
(fn [& ys]
(reduce #(%2 %1)
(apply (last xs) ys) (rest (reverse xs)))))
它有效。但我不太明白 reduce
在这里是如何工作的。它如何表示(apply f_1 (apply f_2 ...(apply f_n-1 (apply f_n args))...)
?
最佳答案
让我们尝试分 3 个阶段修改该解决方案。与每个人待一段时间,看看你是否明白。如果你这样做了就停下来,以免我让你更加困惑。
首先,让我们有更多描述性的名称
(defn my-comp [& fns]
(fn [& args]
(reduce (fn [result-so-far next-fn] (next-fn result-so-far))
(apply (last fns) args) (rest (reverse fns)))))
然后分解一些
(defn my-comp [& fns]
(fn [& args]
(let [ordered-fns (reverse fns)
first-result (apply (first ordered-fns) args)
remaining-fns (rest ordered-fns)]
(reduce
(fn [result-so-far next-fn] (next-fn result-so-far))
first-result
remaining-fns))))
接下来用具有相同功能的循环替换reduce
(defn my-comp [& fns]
(fn [& args]
(let [ordered-fns (reverse fns)
first-result (apply (first ordered-fns) args)]
(loop [result-so-far first-result, remaining-fns (rest ordered-fns)]
(if (empty? remaining-fns)
result-so-far
(let [next-fn (first remaining-fns)]
(recur (next-fn result-so-far), (rest remaining-fns))))))))
关于Clojure:实现 comp 函数,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/21371860/