如何在Clojure中使用不可变数据进行数值模拟?

7 arrays functional-programming clojure immutability numerical-computing

我正在使用Clojure,我需要运行一个小模拟.我有一个长度为n的向量(n通常在10到100之间),它包含值.在每个模拟轮次(可能一起1000轮)中,矢量中的一个值随机更新.我想我可以通过使用Java数组并调用aset方法来实现这一点,但这会破坏函数式编程/不可变性的习惯用法.

有没有更实用的方法来实现这一点,还是应该使用Java数组?

Bri*_*per 6

(defn run-sim [arr num-iters update-fn]
 (if (zero? num-iters)
   arr
   (let [i (rand-int (count arr))
         x (update-fn)]
     (println "setting arr[" i "] to" x)
     (recur (assoc arr i x) (dec num-iters) update-fn))))

user> (run-sim [1 2 3 4 5 6 7 8 9 10] 10 #(rand-int 1000))
setting arr[ 8 ] to 167
setting arr[ 4 ] to 977
setting arr[ 5 ] to 810
setting arr[ 5 ] to 165
setting arr[ 3 ] to 486
setting arr[ 1 ] to 382
setting arr[ 4 ] to 792
setting arr[ 8 ] to 478
setting arr[ 4 ] to 144
setting arr[ 7 ] to 416
[1 382 3 486 144 165 7 416 478 10]
Run Code Online (Sandbox Code Playgroud)

如果你需要它,使用Java数组并不羞耻.特别是如果你需要它快速.将数组变异限制在函数内部(克隆输入数组并对其进行处理)并且没有人会更聪明.


kot*_*rak 5

添加到布莱恩的答案:如果你需要更快的速度,你也可以求助于瞬态.

(defn run-sim
  [vektor num-iters update-fn]
  (loop [vektor    (transient vektor)
         num-iters (int num-iters)]
    (if (zero? num-iters)
      (persistent! vektor)
      (let [i (rand-int (count vektor))
            x (update-fn)]
        (recur (assoc! vektor i x) (dec num-iters))))))
Run Code Online (Sandbox Code Playgroud)