【问题标题】:Why prefer seq over non-empty as a predicate?为什么更喜欢 seq 而不是非空作为谓词?
【发布时间】:2014-03-02 22:12:57
【问题描述】:

empty? 的文档字符串说“请使用成语 (seq x) 而不是 (not (empty?x))”。 MisterMetaphor 指出在if-let 中使用seq 作为谓词是有意义的:

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

我真的应该使用seq 来测试一般的非空性吗? seq 可以将其参数转换为不同的形式。例如:

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,如果非空,则其参数不变。

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

【问题讨论】:

    标签: clojure


    【解决方案1】:

    首先,查看empty?的定义:

    (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

    (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。虽然仅用作谓词,但它只会包装seq

    不过,不要担心seq 会很严厉。它只是返回一个迭代器。它实际上并没有转换整个数据结构。

    【讨论】:

    • 谢谢。令人着迷且令人惊讶的是,任何额外的成本(返回迭代器)都需要为如此频繁使用的操作支付。或者更确切地说,它必须是事实上它完全没有成本,这再次令人着迷。
    • 我当然希望 JIT 编译器在优化双重否定方面没有问题。
    • @remicles2 我无法想象带有惰性片段的动态类型语言的优化会如此火爆。是否有任何论文说明 JIT 在遇到重大障碍之前能够完成多少工作?
    猜你喜欢
    • 2015-08-13
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-09-28
    相关资源
    最近更新 更多