为什么在Clojure中使用种子时不会重复生成可重现的随机数?

too*_*ays 12 random clojure

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

注意:我按如下所示运行下面的每个示例三次以产生给定的结果.

(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]
Run Code Online (Sandbox Code Playgroud)

A. *_*ebb 11

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


Ale*_*lex 5

如果你对其他答案的评论表明,你想要保留懒惰,那么你需要在传递给函数中应用绑定repeatedly,捕获你在lazy seq之外创建的种子.例如:

(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)
Run Code Online (Sandbox Code Playgroud)