我们如何在 Clojure 中同时进行左右折叠? [英] How do we do both left and right folds in Clojure?
问题描述
Reduce 工作正常,但它更像是 fold-left.有没有其他形式的 reduce 可以让我向右折叠?
Reduce works fine but it is more like fold-left. Is there any other form of reduce that lets me fold to right ?
推荐答案
让我们看看每个可能的定义:
Let's look at a possible definition of each:
(defn foldl [f val coll]
(if (empty? coll) val
(foldl f (f val (first coll)) (rest coll))))
(defn foldr [f val coll]
(if (empty? coll) val
(f (foldr f val (rest coll)) (first coll))))
注意只有foldl
在尾部,递归调用可以用recur
代替.所以对于 recur
,foldl
不会占用堆栈空间,而 foldr
会.这就是为什么reduce
就像foldl
.现在让我们尝试一下:
Notice that only foldl
is in tail position, and the recursive call can be replaced by recur
. So with recur
, foldl
will not take up stack space, while foldr
will. That's why reduce
is like foldl
. Now let's try them out:
(foldl + 0 [1 2 3]) ;6
(foldl - 0 [1 2 3]) ;-6
(foldl conj [] [1 2 3]) ;[1 2 3]
(foldl conj '() [1 2 3]) ;(3 2 1)
(foldr + 0 [1 2 3]) ;6
(foldr - 0 [1 2 3]) ;-6
(foldr conj [] [1 2 3]) ;[3 2 1]
(foldr conj '() [1 2 3]) ;(1 2 3)
你有什么理由想要正确弃牌吗?我认为 foldr
最常见的用法是将一个列表从前到后放在一起.在 Clojure 中,我们不需要它,因为我们可以使用向量代替.避免堆栈溢出的另一个选择是使用惰性序列:
Is there some reason you want to fold right? I think the most common usage of foldr
is to put together a list from front to back. In Clojure we don't need that because we can just use a vector instead. Another choice to avoid stack overflow is to use a lazy sequence:
(defn make-list [coll]
(lazy-seq
(cons (first coll) (rest coll))))
所以,如果你想正确弃牌,一些有效的替代方法是
So, if you want to fold right, some efficient alternatives are
- 改用矢量.
- 使用惰性序列.
- 使用
reduced
来短路reduce
. - 如果您真的想潜入兔子洞,请使用换能器.
这篇关于我们如何在 Clojure 中同时进行左右折叠?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!