2024 Clojure 状态调查!分享您的想法。

欢迎!请访问关于页面以了解有关如何使用此工具的一些更多信息。

+39投票
Clojure
编辑

我经常写:(some #(when (pred %) %) ...) 并常常错误地写:(some #(pred %) ...)。我认为将 (some #(when (pred %) %) ...) 作为 clojure.core 中的内置函数可能是有意义的。

建议的名称:first-by。请随意提出其他名称,我会在此列出。

(first-by #(= (:id %) 2) [{:id 1} {:id 2} {:id 3}]) ;;=> {:id 2}

统计信息,在我的本地 .m2 目录中,我发现 198 个 (some #(when ...) ..) 形式和 1503 个 (some #(foo ...) ...) 形式,其中 foo 不是 when。

总 some + fn 使用:1701,其中 11% 是 some + when 形式。

发现这些用法的程序

(ns grasp
  (:require
   [clojure.spec.alpha :as s]
   [grasp.api :as g]))

(s/def ::some+when
  (s/cat :some #{'some}
         :fn (s/spec (s/cat :fn #{'fn 'fn*}
                            :args vector?
                            :when (s/spec (s/cat :when #{'when} :whatever (s/* any?)))))
         :coll any?))

(defn keep-fn [{:keys [spec expr uri]}]
  (let [conformed (s/conform spec expr)]
    (when-not (s/invalid? conformed)
      {:expr expr
       :uri uri})))

(defn -main [& args]
  (let [classpath (first args)
        matches (g/grasp classpath ::some+when {:keep-fn keep-fn})]
    (prn (count matches))))

{:deps {io.github.borkdude/grasp {:mvn/version "0.0.3"}}}

在 grep.app 中,我发现大约 8% 的 some+when 形式的 some 用法。

7 答案

+7投票

我较喜欢像 评论 中提到的 CLJ-2056 中提到的《(first xform coll)》。那个想法被提到了,但我不认为当时被充分讨论。

这比somefirst-by更通用:(some <pred> <coll>)其实就是(first (keep <pred>) <coll>),而(first-by <pred> <coll>)其实就是(first (filter <pred> <coll>)

此外,它的效率可能也比somefirst-by更高。如果您想将它与其他序列函数结合使用,它们可以统一到转换器中,如下所示:

(first (comp (map #(* % %))
             (filter #(> % 100)))
       (range))

而不是

(first-by #(> % 100) (map #(* % %) (range)))
注意,我不想将first-by基于filter实现,因为分块

https://twitter.com/borkdude/status/1567525617549152257
即使这样,也不会受到分块的影响,因为它将使用filter返回的转换器的arity。

差别巨大

(first (filter <pred> <coll>))

(first (filter <pred> <coll>))

编辑
是的,如果我们这样实现它

(defn first' [xf coll]
  (transduce xf (completing (fn [_ x] (reduced x))) nil coll))

它不会引起任何分块。事实上,甚至没有意识到序列的存在。
哦,(完成简化),天才!比基于 xforms 提出的更简洁得多。
抱歉,我的意思是 `(completing (fn [_ x] (reduced x)))`。已修复。
+2

顺便说一下,之前曾经拒绝过类似的提案:[https://clojure.atlassian.net/browse/CLJ-2056](https://clojure.atlassian.net/browse/CLJ-2056)

Alex 的回复很有趣,我确实看到了他的观点。

尽管我同意线性搜索效率低下,但这是在考虑更大的数据集时。我使用此操作最常见的用途是在处理短序列时,例如在处理文本行。为单次查找构建索引结构仍然需要对数据进行线性处理,并且对于短序列来说效率要低得多(与 ArrayMap 比较)。

如果一个不同的结构总是正确的,那么我们就不会有一群人立即对这个问题表示赞同,其中许多人评论说他们经常这样做。
+2

我理解允许或者说支持线性搜索可能会让人一开始就使用错误的数据结构。

然而,对于少量数据的简单线性搜索通常正是正确的事情,但在Clojure中做这件事总是有些尴尬。我认为这种尴尬是坏尴尬,它会导致代码不清晰和错误。

当我需要的时候,我通常在某个工具命名空间中实现Common Lisp中的find-if,因为它使代码非常清晰

(find-if odd? xs)

+1 投票

顺便一提,我宁愿在核心中使用类似于when-valid的东西而不是first-by

(defn when-valid [pred]
  #(when (pred %) %))

它可以与some组合使用

(some (when-valid pos?) [-1 0 2]) => 2

它也可以与some-fn一起使用

((some-fn (when-valid string?) (when-valid pos?)) "foo") => "foo"
((some-fn (when-valid string?) (when-valid pos?)) -5) => nil

编辑
我最近对此类函数的版本是 `select`

```
(defn select
  "如果`(pred x)`是逻辑真,则返回`x`,否则返回`nil`。
   如果是一元arity,则返回函数`(select % pred)`。
  ([pred]
   #(select % pred))
  ([x pred]
   (when (pred x) x)))

(some-> x (select number?) inc)

(keep (select pos?) xs)
```
嗯,这么一来,人们也可以对此进行点赞 https://ask.clojure.org/index.php/8945/something-like-when-pred-in-the-core
+1 投票

编辑

使用cgrand/xforms,我通常会通过以下方式解决这个问题:x/some(x/some (filter <pred>) coll),只要我要返回的项目不是nil,它就有效。

根据 xforms 代码的一个潜在实现可能看起来像这样

(defn rf-first
  "Reducing function that returns the first value."
  ([] nil)
  ([x] x)
  ([_ x] (reduced x))) 

(defn xf-first
  "Process coll through the specified xform and returns the first value."
  [xform coll]
  (transduce xform rf-first nil coll))

(xf-first (filter <pred>) coll)
这种做法与分块处理兼容得如何? some 与 when 不进行分块处理
你在哪里看到了分块处理?
没有任何地方,现在我明白了。
0

我每天都在做同样的事情!好评。

我个人将这个函数称为“find”,并这样定义。这就是我在其他语言和过去的函数库中看到它被称呼的方式。我认为“first”是解决方案的一部分,但当我想到名字时,它并不合适,因为它是filter+first,两者都是相等的组成部分,所以我觉得名字应该描述两者的组合。
我选择了`ffilter`,因为另一种方法是使用`filter`和`first`包装
0

编辑

正如另一位回答者提到的,这曾经被考虑并且被拒绝。我觉得从那时起没有变化。

关于这个的轶事不太有用,但数据很有用。如果您可以使用grep.app或grasp或其他工具收集使用数据,将会很有帮助。还有一点也很有用,即有一份现有类似函数的常用库的清单以及它们的用法(如果有差异,它们的实现方式也不同)。

此外,从更好地考虑一个使用语料库的角度来处理这个问题可能是有用的,看看是否存在更深层次或更有趣的共同点或问题,这可能有一些其他替代解决方案。

我现在正在处理一些数据。
添加到原始帖子的数据。
...