【问题标题】:Why doesn't repeatedly generate reproducible random numbers when using a seed in Clojure?为什么在 Clojure 中使用种子时不会重复生成可重现的随机数?
【发布时间】:2014-03-16 19:37:26
【问题描述】:

我有一些函数需要一系列随机数,所以我采用了一些简单的原语,例如 #(inc (g/uniform 0 n)),但我似乎无法生成可重现的随机数系列,即使我正在重新绑定 @987654322 @,除非我如下所示生成它们。我无法想象这是最好的方法,所以有人能指出如何做得更好吗?

注意:如下所示,我将每个示例运行 3 次以产生给定的结果。

(ns example.show
  (:require [clojure.data.generators :as g]))


(binding [g/*rnd* (java.util.Random. 42)]
  (take 10 (repeatedly #(inc (g/uniform 0 n))))

=> (9 4 5 4 4 5 1 8 2 9)

=> (2 1 1 6 3 10 10 4 1 9)

=> (10 4 7 8 9 6 10 1 8 3)


(binding [g/*rnd* (java.util.Random. 42)]
  (g/reps 10 #(inc (g/uniform 0 n)))

=> (3 9 4 6 3 8 6 6 5 4)

=> (7 8 4 7 7 5 7 4 8 7)

=> (2 8 7 8 8 8 9 2 6 5)

;; This seems to work
(binding [g/*rnd* (java.util.Random. 42)]
  (letfn [(roll [n] #(inc (g/uniform 0 n)))]
    [((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10)) ((roll 10))]))

=> [8 7 4 3 7 10 4 3 5 8]

=> [8 7 4 3 7 10 4 3 5 8]

=> [8 7 4 3 7 10 4 3 5 8]

【问题讨论】:

    标签: random clojure


    【解决方案1】:

    因为懒惰。在序列实现之前,您从binding 返回。因此,惰性序列永远不会看到您设置的绑定。一种解决方案是在绑定内的序列上强制实现doall

    【讨论】:

    • 我认为惰性求值只是延迟了执行,也许是通过将参数包装在一个闭包中,这会影响任何其他特定于订单的消费函数吗?如果没有doall,我该如何处理它,因为我的计算可能很昂贵,而且我不想放弃懒惰。
    • 请参阅kotka.de/blog/2009/11/Taming_the_Bound_Seq.html 了解解释和解决方法。
    【解决方案2】:

    如果正如您对另一个答案的评论所表明的那样,您想要保留惰性,那么您需要在传递给repeatedly 的函数中应用绑定,捕获您在惰性序列之外创建的种子。例如:

    (defn rand-seq [seed]
      (let [r (java.util.Random. seed)]
        (repeatedly #(binding [g/*rnd* r]
                       (inc (g/uniform 0 10))))))
    
    (take 10 (rand-seq 42))
    #=> (8 7 4 3 7 10 4 3 5 8)
    
    (take 10 (rand-seq 42))
    #=> (8 7 4 3 7 10 4 3 5 8)
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-12-10
      • 2017-05-02
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2011-05-06
      • 2019-02-14
      相关资源
      最近更新 更多