Clojure 列表中的惯用语和懒惰最终是真实的

Idiomatic and lazy eventually truthy in a list in Clojure

我想要一个 function/macro 来检查列表最终是否具有真实值,我希望评估是懒惰的。这是我没有惰性评估的说明性实现:

(defn eventual [cols]
  (or (first cols) (if-let [rs (rest cols)]
                     (eventual rs))
                     false))

这里有一个简单的例子来说明:

(if (eventual [false (+ 1 2) (* 10000 10000)])
  true
  false)

我觉得这其中一定有惰性求值的含义。也许我现在只是瞎了眼。请帮忙帮忙。谢谢

您可以使用 some 函数检查一个序列是否包含至少一个真值元素:

(some identity col)

如果您将惰性序列作为 col 传递给它,它将计算其内容直到第一个真值元素,而不会实现其余部分:

(let [col (take
            10
            (iterate
              #(do (println "Generating new value from " %) (inc %))
              0))]
  (some #(> % 5) col))

产生:

Generating new value from  0
Generating new value from  1
Generating new value from  2
Generating new value from  3
Generating new value from  4
Generating new value from  5
true

如您所见,值 6..9 根本没有生成。

您还应该仔细检查您传递给 somecol 是否真的很懒惰并且尚未实现,因为它可能会让您感到困惑。

您的 eventual 函数已尽其所能。它急切地搜索第一个真实的项目然后停止。但它有问题:

  • 它无法在空集合上终止。 (rest ())(), 这是真实的。使用 next 而不是 rest(next ())nil, 这是虚假的。
  • 它是真正的递归。它会吹足够长的堆栈 搜索。尝试 (eventual (repeat false))。因为递归是 尾递归,你可以通过在它的位置使用 recur 来解决这个问题。
  • 虽然我们在这里,但 return nil 是惯用的,而不是 false, 在 运行 出一个集合。所以放弃最后的 false.

我们最终得到

(defn eventual [cols]
  (or (first cols) (if-let [rs (next cols)]
                     (recur rs))))

我对 cols 为空时会发生什么感到有点不安。基于 the source for some 的代码更清晰:

(defn eventual [coll]
    (when (seq coll)
      (or (first coll) (recur next coll))))

但是,正如 所建议的,使用 (some identity col) 可能是最好的。