Clojure:惯用的召唤方式包含?在一个懒惰的序列

时间:2013-04-28 16:07:27

标签: clojure lazy-sequences

是否有一种惯用的方法来确定LazySeq是否包含元素?从Clojure 1.5开始,调用contains?会抛出IllegalArgumentException:

IllegalArgumentException contains? not supported on type: clojure.lang.LazySeq      
clojure.lang.RT.contains (RT.java:724)

在1.5之前,据我所知,它总是返回false。

我知道在LazySeq上调用contains?可能永远不会返回,因为它可以是无限的。但是如果我知道它不是并且不关心它是否被热切评估呢?

我想出的是:

(defn lazy-contains? [col key]
  (not (empty? (filter #(= key %) col))))

但感觉不太对劲。还有更好的方法吗?

2 个答案:

答案 0 :(得分:11)

首先,懒惰的seqs无法有效检查会员资格。考虑使用集合而不是惰性seq。

如果一套不切实际,你的解决方案也不错。一些可能的改进:

  1. “非空”有点尴尬。只使用seq就足以获得用户可以在if中使用的nil-or-truthy值。如果你想要true或false,你可以用布尔值包装它。

  2. 由于您只关心第一场比赛,您可以使用一些而不是过滤器和seq。

  3. 编写等式谓词的一种简便方法是使用文字集,如#{key},但如果key为nil,则无论nil是否为n,都将返回nil。

  4. 所有这些一起给你:

    (defn lazy-contains? [col key]
      (some #{key} col))
    

答案 1 :(得分:4)

如果您在示例中使用some而不是filter,则会在找到值后立即返回,而不是强制评估整个序列。

(defn lazy-contains? [coll key]
  (boolean (some #(= % key) coll)))

修改:如果您没有将结果强制转换为布尔值,请注意,如果找不到密钥,您将获得nil而不是false