我刚刚完成了4clojure Problem 60,这是我的第一个带有问题描述的程序的代码:
;;Write a function which behaves like reduce, but returns each intermediate
;;value of the reduction. Your function must accept either two or three arguments,
;;and the return sequence must be lazy.
(fn red
([fun sq]
(red fun (first sq) (rest sq)))
([fun acum sq]
(if (empty? sq) acum
(cons acum (lazy-seq (red fun (fun acum (first sq)) (rest sq)))))))
函数的核心在if下面出现一行,我只返回初始值,然后将它应用到序列中的下一个元素。但它涉及向量的第二个测试案例失败了:
user=> (red conj [1] [2 3 4])
([1] [1 2] [1 2 3] 1 2 3 4);; it should be ([1] [1 2] [1 2 3] [1 2 3 4])
我花了一些时间才意识到问题是cons
只是添加vector
[1 2 3 4]
,因为它是列表的其余部分而不是单个元素。
我所做的是将cons
转换为concat
和acum
转换为[acum]
并且它有效:
(fn red
([fun sq]
(red fun (first sq) (rest sq)))
([fun acum sq]
(if (empty? sq) [acum]
(concat [acum] (lazy-seq
(red fun (fun acum (first sq)) (rest sq)))))))
不要问我原因,但在我看来有点不优雅,其他解决方案也没有使用concat
。
问题是,考虑到第一个函数,在不修改代码的情况下,什么函数/宏可以工作。
答案 0 :(得分:3)
在if
true case返回[acum]
而不是acum
答案 1 :(得分:0)
如果你改用cons,你可以避免使用concat。缺点是懒惰(参见Stack Overflow上关于cons与conj的讨论):
(defn my-reductions
([f sq] (my-reductions f (first sq) (rest sq)))
([f init sq]
(if (empty? sq)
(list init)
(cons init (lazy-seq (my-reductions f (f init (first sq)) (rest sq))))
)
)
)
顺便说一句:这段代码通过了4Clojure测试,但并不像所有情况下的减少那样:
(my-reductions + [])
(nil)
(reductions + [])
(0)