我想为每次调用递归函数创建几个项目,并收集列表中的所有内容。也就是说,我想做这样的事情:
(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。我想避免使用全局变量。
答案 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)))