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 根本没有生成。
您还应该仔细检查您传递给 some
的 col
是否真的很懒惰并且尚未实现,因为它可能会让您感到困惑。
您的 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)
可能是最好的。
我想要一个 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 根本没有生成。
您还应该仔细检查您传递给 some
的 col
是否真的很懒惰并且尚未实现,因为它可能会让您感到困惑。
您的 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)
可能是最好的。