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来确保集合是向量或集合,因为将nil加上元素会创建一个列表,而我几乎从不使用列表。
  2. 必须对所有进入系统的集合在边界上通过not-empty进行处理。

您觉得呢?

3 个回答

+3

在我看来,您考虑得太多了。我会以简洁明了的方式来编写我的函数,如果遇到空集合,最终返回nil或空序列,那就这样吧。除非我知道这个函数将在特定情境下使用,并且确实需要返回nil或空序列,否则我不会刻意将其设置为其中之一。它应该是从简单明了的实现中自然而然产生的。

从性能的角度来看,情况类似。这是一个微优化,如您所述,为了强制执行它,您可能需要牺牲代码的可读性和简洁性,例如现在可能需要处理conj或其他情况。此外,由于它仅依赖于良好的意图,因此似乎很难一致地维护这种模式。因此,我认为在这里您也想得太多了。同样地,除非我处于绝对的性能关键用例中,并且已经用尽所有其他方法,并且我的分析表明删除条件中的seq空检查可以节省相当多的时间,否则我不会为此烦恼,而且还只为那些测试中显示出现热点的函数烦恼。

+1
by

我认为,如果您熟悉(普遍、文档化的)用法惯例,(seq xs)就不会比其他的内容不明确。我认为fnil难以理解,而not-empty也很繁琐。的确,在我看来,使用seq比那些更可取。

我认为一个更有影响的选择是在映射中避免将nil作为值。

...