如何为递归函数的每次迭代收集多个项目

时间:2013-01-31 00:38:58

标签: recursion clojure lisp

我想为每次调用递归函数创建几个项目,并收集列表中的所有内容。也就是说,我想做这样的事情:

(defn myfunc [x]
  (loop [x x retur '()]
    (when condition1
      (let [templist '()]
        (if condition2 (def templist (conj templist {:somekey someval})))
        (if condition3 (def templist (conj templist {:somekey someval})))
        (recur (+ x 1) (concat retur templist))))))

问题是在Clojure中我无法重新绑定let。我想避免使用全局变量。

3 个答案:

答案 0 :(得分:3)

核心中的一些功能使用这种通过let链接相同符号的模式来有条件地建立一个值。我不得不将contition1更改为一个永远不会循环的示例,并将when更改为if,它可以在循环结束时返回一个值。

(defn myfunc [x someval1 someval2 condition1 condition2 condition3]
  (loop [x x retur '()]
    (if (condition1 x)
      (let [templist '()
            templist (if condition2 (conj templist {:somekey1 someval1}) templist)
            templist (if condition3 (conj templist {:somekey2 someval2}) templist)]
        (recur (+ x 1) (concat retur templist)))
      retur)))

然后可以测试:

 user> (myfunc 0 1 2 #(< % 5) true true)
 ({:somekey2 2} {:somekey1 1} {:somekey2 2} {:somekey1 1} {:somekey2 2} 
  {:somekey1 1} {:somekey2 2} {:somekey1 1} {:somekey2 2} {:somekey1 1})

user> (myfunc 0 1 2 #(< % 5) true false)
({:somekey1 1} {:somekey1 1} {:somekey1 1} {:somekey1 1} {:somekey1 1})

let中的想法是让每个阶段在条件为真时更改值,或者如果条件为假则返回不变。这种模式为功能代码提供了必要的外观,并且可以帮助明确如何构造一个值,尽管使用它来将命令式逻辑“转换”为功能性程序也可以用得太过分。

答案 1 :(得分:1)

每当我需要进行一些面向步骤的操作时,我更喜欢使用线程宏->

(defn myfunc [x]
  (loop [x x retur '()]
    (when condition1
        (let [r (-> '()
                    (#(if condition2 (conj % {:somekey 1}) %))
                    (#(if condition3 (conj % {:somekey 2}) %)))]
        (recur (+ x 1) (concat retur r))))))

答案 2 :(得分:0)

您尝试使用通过分配链获得结果的命令式模式。而不是这样你可以尝试以更具声明性的方式解决你的问题,这对于作为功能语言的clojure更为惯用。例如

(defn myfunc [x]
  (loop [x x retur '()]
    (if condition1
      (recur (inc x) (concat retur
                             (when condition2 [{:somekey1 someval1}])
                             (when condition3 [{:somekey2 someval2}])))
      retur)))