Clojure 中是否有一个相当于“first”的归约函数?

Is there a reducing function in Clojure that performs the equivalent of `first`?

我经常写这种形式的代码

(->> init
     (map ...)
     (filter ...)
     (first))

将其转换为使用转换器的代码时,我会得到类似

的结果
(transduce (comp (map ...) (filter ...)) (completing #(reduced %2)) nil init)

(completing #(reduced %2)) 而不是 first 根本不适合我。它不必要地掩盖了一个非常简单的任务。是否有更惯用的方式来执行此任务?

medley has find-first with a transducer arity and xforms 有一个称为 last 的归约函数。我认为两者的结合就是您所追求的。

(ns foo.bar
  (:require
   [medley.core :as medley]
   [net.cgrand.xforms.rfs :as rfs]))

(transduce (comp (map ,,,) (medley/find-first ,,,)) rfs/last init)

我个人会使用你的方法和自定义减少函数,但这里有一些替代方法:

(let [[x] (into [] (comp (map inc) (filter even?) (take 1)) [0 1])]
    x)

使用解构:/

或者:

(first (eduction (map inc) (filter even?) [0 1])

在这里,您可以节省调用 comp 的费用,这是为您完成的。虽然它不是超级懒惰。它会实现多达 32 个元素,因此可能会造成浪费。 固定为 (take 1):

(first (eduction (map inc) (filter even?) (take 1) [0 1]))

与以下相比,整体更短且不太清晰:

(transduce (comp (map inc) (filter even?) (take 1)) (completing #(reduced %2)) nil [0 1])

如果你大量需要这个,那么我可能 NOT 创建一个自定义 reducer 函数,而是创建一个类似于 transduce 的函数,它以 xform, coll 作为参数returns 第一个值。它的作用更清楚,你可以给它一个很好的文档字符串。如果你想节省调用 comp 你也可以使它类似于 eduction:

(defn single-xf
  "Returns the first item of transducing the xforms over collection"
  {:arglists '([xform* coll])}
  [& xforms]
  (transduce (apply comp (butlast xforms)) (completing #(reduced %2)) nil (last xforms)))

示例:

(single-xf (map inc) (filter even?) [0 1])