在DrRacket中返回列表而不改变使用foldr这样做:
(foldr cons '() '(1 2 3))
然而在Clojure中,减少是折叠,所以我该怎么做?
首先我尝试了这个:
(reduce cons '() '(1 2 3))
=> IllegalArgumentException Don't know how to create ISeq from: java.lang.Long clojure.lang.RT.seqFrom (RT.java:542)
之后我尝试了这个:
(reduce conj '() '(1 2 3))
=> (3 2 1)
“=>” 中是REPL中的输出
不,我不想读Clojure如何实现减少。我已经知道了。这是一个更具体的问题。我自己找到了答案,我会发布。
答案 0 :(得分:3)
在你的第二次尝试中,你必须"翻转"传递给利弊的论据:
(reduce #(cons %2 %1) '() '(1 2 3))
=> (3 2 1)
但是,正如您所注意到的,reduce实际上是一个向左折叠,因此原始列表中的第一个项目成为结果列表中最内部(或最后)的项目。这可以通过reverse
处理:
(reduce (fn[a b](cons b a)) '() (reverse '(1 2 3)))
=> (1 2 3)
您可以详细了解为什么clojure缺乏' foldr in here
答案 1 :(得分:0)
我对Racket并不熟悉,但Clojure的reduce
似乎与两个主要方面的Racket foldr
不同:
reduce
从头到尾处理列表(与foldr
的尾部相对)。在这方面,reduce
类似于foldl
。reduce
将累计值作为 first 参数传递给reduce函数(与foldr
/ {{1的 last 参数相对}})。第二个区别是使用foldl
时出错的原因 - cons
是第一次拨打电话,(cons '() 1)
显然不是列表。
如果我们认为当1
是列表时(conj xs x)
等同于(cons x xs)
,那么xs
相当于(reduce conj '() '(1 2 3))
,这可能会更加明显写成
(cons 3 (cons 2 (cons 1 '())))
现在,如果你不介意结果是向量而不是列表,你可以这样做:
(->> '()
(cons 1)
(cons 2)
(cons 3))
或者,如果您愿意,可以将结果转换为(reduce conj [] '(1 2 3))
,以便它基本上像列表一样:
seq
或者,您可以(seq (reduce conj [] '(1 2 3)))
输入列表:
reverse
答案 2 :(得分:0)
这是我的解决方案。我不知道它有多高效。在Racket课程中我们在大学里使用过这种解决方案。
(reduce #(concat %1 (list %2)) '() '(1 2 3))
=> (1 2 3)