在clojure中跟踪先前值的惯用方法是什么?

时间:2014-06-30 18:43:07

标签: clojure

(defmethod learn [:SARSA :Module] [learner module] 
  (let [samples (get learner :dataset)]  
    (for [seq samples]
      (let [laststate (atom 0) lastaction (atom 0) lastreward (atom 0)])
       ;;Do some stuff
       ;;Update laststate,lastaction,lastreward

      )

    ))

我使用for循环迭代序列,但也许我应该使用常规循环并重复? map / reduce在这里有用吗?

2 个答案:

答案 0 :(得分:6)

小心 - 在Clojure中,最好不要将for视为一个循环,而是作为一个列表理解 - 它需要一个集合并返回该集合的修改/过滤版本

你可以通过使用循环和recur来更加惯用(在更多函数式编程风格中)这样做:

(defmethod learn [:SARSA Module] [learner module]
  (loop [samples (get learner :dataset)
         last-state 0
         last-action 0
         last-reward 0]
    (if-let [sample (first samples)]
      (recur (next samples) (new-last-state) (new-last-action) (new-last-reward))
      [last-state last-action last-reward])))

每次使用last-statelast-actionlast-reward的新值进行迭代时,(if-let [sample (first samples)]部分会确定是否还有任何样本需要查看 - 如果没有,这意味着您已经在列表的末尾,而(first '())将返回nil,因此您的结果将以您喜欢的任何形式返回 - 看到最后一行,我把它们作为向量返回。如果还有剩余样本,我们会将第一个标记绑定到符号sample,您可以将其用于last-state等的更新计算,然后recur使用这些更新后的值和(next samples),这是该列表中第一个样本之后的所有内容。

编辑:我通常会尝试使用map / reduce做任何事情,但是每当你尝试进行复杂的循环操作时,你会计算并计算一些不同的统计数据,loop / recur就是通常是最好的方式。

答案 1 :(得分:5)

@DaveYarwood在答案中提到map / reduce;这是你如何实现它:

(defmethod learn [:SARSA Module] [learner module]
  (reduce (fn [[state action reward] sample]
            ;; do some stuff and computes new values for state/action/reward
            [new-state new-action new-reward])
          [0 0 0]
          (get learner :dataset)))