合并同一集合的函数

Combine functions for same collection

我刚开始学习Clojure,我习惯于使用其他函数式语言创建一些具有

等功能的管道
val result = filter(something)
             map(something)
             reduce(something)
         collection

我正在尝试通过结合两个 filter 函数的 Clojure 实现类似的东西

(defn filter-1 [array] (filter
                         (fn [word] (or (= word "politrons") (= word "hello"))) array))
(defn filter-2 [array] (filter
                         (fn [word] (= word "politrons")) array))

(def result (filter-1 ["hello" "politrons" "welcome" "to" "functional" "lisp" ""]))

(println "First:" result)

(println "Pipeline:" ((filter-2 result)))

但我无法让它工作。

能否就如何将两个 predicate 函数组合成同一个 collection 提供一些建议或文档?

此致

您的两个 filter-$ 功能已经完全成熟(请注意,您 将通过使您的谓词发挥作用而不是获得更多的可重用性 隐藏谓词的整个过滤)。

因此,要实现这一点,您可以使用 thread-last 宏 ->>:

(->> array
     filter-1
     filter-2)

这是一种相当通用的方法,您会经常在代码中看到 在野外。更一般:

(->> xs
     (filter pred?)
     (map tf)
     (remove pred?))

更新的方法是 transducers,其中 组合是通过 comp 完成的。这也是 实际上将您的整个转换管道组合成一个新函数。

例如

(def my-xf
 (comp 
   (filter pred1)
   (filter pred2)))

(into [] my-xf xs)

注意在 filter 上使用单参数版本。

有一些组合处理步骤的选项:

您可以像这样通过管道过滤调用:

   (->> data
        (filter #{"politrons" "hello"})
        (filter #{"politrons"}))
   ;;=> ("politrons")

注意这些词集用作过滤函数(只是你那些相等谓词的快捷方式)

但我猜你需要知道的是 transducers 概念,因为它的用法包括(但不限于)你需要的这种流水线:

(eduction (filter #{"politrons" "hello"})
          (filter #{"hello"})
          data)
;;=> ("hello")

如果您只需要过滤,您还可以将过滤功能与更高级别的功能结合使用,例如 every-pred:

(filter (every-pred #{"politrons" "hello"}
                    #(= "olleh" (clojure.string/reverse %)))
        data)
;;=> ("hello")