Clojure:实现 comp 函数

标签 clojure

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/

相关文章:

Clojure 内置函数来访问整个记录

clojure - 如何从列表中删除多个项目?

maven - 在 Maven 风格的项目布局中找不到 lobos.migrations

java - 如何直接从 Java 调用 Clojure 函数

Clojure 引用项目是最新的吗?

clojure - 如何在 Clojure 中扩展数值协议(protocol)

clojure - 编写函数时 “true” 有什么用,给定键和映射,返回 “true”

clojure - 将 var 或 #' 应用于 Clojure 中的函数列表

clojure - 访问 Compojure 查询字符串

javascript - Clojurescript、JavaScript、SVG、图表、图形