请分享您的想法,参加2024 Clojure现状调查!

欢迎!请访问关于页面获取更多有关这个网站如何工作的信息。

+5
集合

这是一个关于Clojure三个不同方面的交叉问题

  1. 集合函数将nil视为空集合。像filtermap甚至assoc这样的函数可以高兴地接受nil作为coll。
  2. if和衍生的宏(whenandor等)将nil视为假值。
  3. empty?将其输入强制转换为seq,这会导致不必要的分配,而使用seq来检查非空性(而不是(not (empty? xs)))是一种常见的惯例。这是因为(not (empty? xs))的意图感觉比seq更清晰。

话虽如此,我觉得有意识地将在应用程序中以nil表示每个空集合可能是有用的,因为这是更高效和更清晰的:

(let [xs (get-non-empty-coll-or-nil)]
  (if xs
    (do-stuff-with xs)
    (do-nothing)))

...这比这更好

(let [xs (get-possibly-empty-coll)]
  (if (seq xs)
    (do-stuff-with xs)
    (do-nothing)))

我认为这种方法有两个缺点

  1. 必须使用(fnil conj [])(fnil conj #{})而不是conj来确保集合是向量/集合,因为将conj应用到nil会创建一个列表,而我个人几乎从不使用列表。
  2. 必须对所有传入系统的集合边界运行not-empty

您怎么看?

3 答案

+3
by

在我看来,您想得太多了。我会以可读和简单的方式编写我的函数,如果它们在空coll的情况下返回nil或空序列,那就这样吧。除非我知道这个函数将在需要nil或空序列的具体环境中使用,否则不会特意让它变成一个或另一个。它会是我找到的最简单、最清晰的实现中自然产生的任何一种。

性能角度类似。这是一个微观优化,如您所述,强制实施它可能需要污染代码的可读性和简洁性,例如现在您需要处理 conj 或其他情况。这也似乎很难一致地维护这种模式,因为它仅取决于良好的意图。因此,我认为在这里您也想得太多了。和之前一样,除非我在一个绝对的性能关键用例中,并且用尽所有其他方法,并且我的分析表明移除在条件中用于空检查的 seq 可以节省一定时间,否则我不会在意这种细节,而且在仍然只是针对在它周围显示热点位置的已分析函数。

+1
by

相关请求:[当 seq 和 if-seq 作为简写宏时的不同行为](https://ask.clojure.org/index.php/10450/when-seq-and-if-seq-as-short-hand-macros)

+1
by

我认为,如果您了解使用它的(普遍的、有文档记载)习语,则 (seq xs) 并不比其他表达更不清晰。我认为 fnil 很难以心理上解析,而不-empty 也相当繁琐。当然,我发现使用 seq 比这些更优选。

我认为避免在映射中放置值为 nil 的属性是一个更有影响的选择。

...