4clojure函数中的连接序列

时间:2014-04-18 02:02:40

标签: clojure

我刚刚完成了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转换为concatacum转换为[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

问题是,考虑到第一个函数,在不修改代码的情况下,什么函数/宏可以工作。

2 个答案:

答案 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)