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形式的用法。

7个答案

+7

我更倾向于使用一个类似 (first xform coll) 的方法,如评论中提到的,在CLJ-2056 上。虽然这个想法在那儿被提及,但我觉得当时并没有完全讨论。

这比 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)))
by
注意,我不想基于filter实现first-by,因为chunking

https://twitter.com/borkdude/status/1567525617549152257
by
(first xform coll) 不会受到chunking的影响,因为它将使用filter返回transducer的arity。

有很多不同之处

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

(first (filter <pred> <coll>))
by by
嗯,如果我们这样实现它

(defn first'[xf coll]
    ;(reduced x))) nil coll))

则不会引起任何chunking。实际上,它甚至没有意识到序列。
啊,(完成了简化),聪明!比基于xforms我提出的要简洁得多。
对不起,我是指`(completing (fn [_ x] (reduced x)))`。已修复。
+2

顺便提一下,之前有类似的提议被拒绝过:[链接](https://clojure.atlassian.net/browse/CLJ-2056)

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

话虽如此,虽然我承认对于大型数据集来说,线性搜索效率不高,但我的这个操作通常用在处理短序列上,比如在处理文本行时。为单个查询建立索引结构仍然需要线性处理数据,而且对于短序列来说效率要低得多(与ArrayMap相比)。

如果不同的结构总是正确的方案,那么我们就不会有一打的人立刻对这个工单进行投票,其中我们中有好几个人评论说,我们总是在这样做。
+2
死 by

我理解允许甚至支持顺序搜索可能会导致人们一开始就使用错误的数据结构。

然而,通常在小集合上进行简单的顺序搜索正是正确的事情,而且在Clojure中这样做总有点别扭。我认为这是一种不好的别扭,它会导致不清晰和错误。

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

(find-if odd? xs)

+1
死 by

只是想提一下,我更喜欢在核心库中使用类似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
死 by
编辑 by
我这种函数的最新版本是`select`。

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

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

(keep (select pos?) xs)
```
by
+1
by
编辑 by

使用 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)
by
这与分块如何结合? some + when 不能分块
by
你在哪里看到分块的?
现在我觉得这很有道理。
0

我每天都在做同样的事情!已点赞。

我把它个人称为 "find",定义为这样。这是我在其他语言和过去的功能库中看到的方式。我 认为 "first" 是解决问题的关键部分,但不是我想用作名称的,因为它是 filter+first,它们都是等价的组成部分,所以我感觉名称应该描述两种混合的结合。
我选择使用 `ffilter`,因为另一种处理方式是将 `filter` 与 `first` 包裹起来
0

编辑过

如另一答案中所述,这曾在过去被考虑并拒绝。我认为此后并没有什么变化。

关于这一点的故事并不特别有用,但数据是。如果你能使用 grep.app 或 grasp 或其他工具收集使用数据,那将是很有帮助的。列出现有通用库中的类似函数及其用法(以及它们如何不同,如果有的话)也很有用。

另外,也许可以从更好的考虑使用案例库的角度来解决这个问题,看看是否有更深或更有趣的共性或问题,可能还有其他替代解决方案。

我现在正在处理一些数据。
已向原始帖子中添加数据。
...