关于clojure:为什么将seq优先于非空作为谓词?

Why prefer seq over non-empty as a predicate?

empty?的文档字符串说:"请使用成语(seq x)而不是(not(empty?x))"。 MisterMetaphor指出,在if-let

中使用seq作为谓词可能很有意义。

1
2
3
(if-let [s (seq might-be-empty)]
   (fn-for-non-empty-seq s)
   (fn-for-empty-seq))

我是否应该真的使用seq来测试非空性? seq可以将其参数转换为其他形式。例如:

1
2
3
4
5
6
7
8
user=> (class (lazy-seq '(1 2 3)))
clojure.lang.LazySeq
user=> (class (seq (lazy-seq '(1 2 3))))
clojure.lang.PersistentList
user=> (class (map inc [1 2 3]))
clojure.lang.LazySeq
user=> (class (seq (map inc [1 2 3])))
clojure.lang.ChunkedCons

如果只是想测试非空性,不需要新的绑定,或者如果我不需要在绑定之前进行转换,那似乎是周期的浪费。在这种情况下not-empty会不是更好的选择?如果参数为空,则返回nil;如果参数为非空,则返回其参数不变。

1
2
3
(if (not-empty [])
 "more to do"
 "all done")

首先,检查empty?的定义:

1
2
3
4
5
6
(defn empty?
 "Returns true if coll has no items - same as (not (seq coll)).
  Please use the idiom (seq x) rather than (not (empty? x))"
  {:added"1.0"
  :static true}
  [coll] (not (seq coll)))

所以empty?(not (seq coll))。这就是为什么不建议对empty?进行补充的原因,因为您对seq进行了双重否定。

现在请参阅not-empty

1
2
3
4
5
(defn not-empty
 "If coll is empty, returns nil, else coll"
  {:added"1.0"
   :static true}
  [coll] (when (seq coll) coll))

惊奇,它也使用seq作为非空性的测试。如果类型很重要,此not-empty很有用-向量上的nth性能,conj行为等。-因为它会按原样返回非空colls。但是,仅用作谓词,只会packageseq

请不要担心seq举手之劳。它所做的只是返回一个迭代器。它实际上并不转换整个数据结构。