1

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

(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。我想避免使用全局变量。

4

3 回答 3

3

核心中的一些函数使用这种通过 a 链接相同符号的模式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 中的想法是,如果条件为真,则让每个阶段更改值,或者如果条件为假,则将其原封不动地返回。这种模式为函数式代码提供了命令式的外观,并有助于明确值是如何构造的,尽管在使用它将命令式逻辑“转换”为函数式程序时也可能太过分了。

于 2013-01-31T01:04:30.610 回答
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))))))
于 2013-01-31T05:12:18.007 回答
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)))
于 2013-01-31T00:50:13.843 回答