如何在clojure中创建一个惰性随机数序列
Posted
技术标签:
【中文标题】如何在clojure中创建一个惰性随机数序列【英文标题】:How to create a lazy sequence of random numbers in clojure 【发布时间】:2012-07-30 23:08:12 【问题描述】:如何创建惰性随机数序列?
我当前的代码:
(import '(java.util Random))
(def r (new Random))
(defn rnd [_]
(.nextInt r 10))
(defn random-numbers [max]
(iterate #(.nextInt r max) (.nextInt r max)))
(println (take 5 (random-numbers 10)))
执行它会引发异常:
(线程“main”clojure.lang.ArityException 中的异常:传递给的 args (1) 数量错误:user$random-numbers$fn 在 clojure.lang.AFn.throwArity(AFn.java:437) 在 clojure.lang.AFn.invoke(AFn.java:39) 在 clojure.core$iterate$fn__3870.invoke(core.clj:2596) 在 clojure.lang.LazySeq.sval(LazySeq.java:42) 在 clojure.lang.LazySeq.seq(LazySeq.java:60) 在 clojure.lang.RT.seq(RT.java:466) 在 clojure.core$seq.invoke(core.clj:133) 在 clojure.core$take$fn__3836.invoke(core.clj:2499) 在 clojure.lang.LazySeq.sval(LazySeq.java:42) 在 clojure.lang.LazySeq.seq(LazySeq.java:60) 在 clojure.lang.Cons.next(Cons.java:39) 在 clojure.lang.RT.next(RT.java:580) 在 clojure.core$next.invoke(core.clj:64) 在 clojure.core$nthnext.invoke(core.clj:2752) 在 clojure.core$print_sequential.invoke(core_print.clj:57) 在 clojure.core$fn__4990.invoke(core_print.clj:140) 在 clojure.lang.MultiFn.invoke(MultiFn.java:167) 在 clojure.core$pr_on.invoke(core.clj:3264) 在 clojure.core$pr.invoke(core.clj:3276) 在 clojure.lang.AFn.applyToHelper(AFn.java:161) 在 clojure.lang.RestFn.applyTo(RestFn.java:132) 在 clojure.core$apply.invoke(core.clj:600) 在 clojure.core$prn.doInvoke(core.clj:3309) 在 clojure.lang.RestFn.applyTo(RestFn.java:137) 在 clojure.core$apply.invoke(core.clj:600) 在 clojure.core$println.doInvoke(core.clj:3329) 在 clojure.lang.RestFn.invoke(RestFn.java:408) 在用户 $eval7.invoke(testing.clj:12) 在 clojure.lang.Compiler.eval(Compiler.java:6465) 在 clojure.lang.Compiler.load(Compiler.java:6902) 在 clojure.lang.Compiler.loadFile(Compiler.java:6863) 在 clojure.main$load_script.invoke(main.clj:282) 在 clojure.main$script_opt.invoke(main.clj:342) 在 clojure.main$main.doInvoke(main.clj:426) 在 clojure.lang.RestFn.invoke(RestFn.java:408) 在 clojure.lang.Var.invoke(Var.java:401) 在 clojure.lang.AFn.applyToHelper(AFn.java:161) 在 clojure.lang.Var.applyTo(Var.java:518) 在 clojure.main.main(main.java:37) [3.8s 完成,退出码 1]
这是一个完全错误的方法,因为我使用的是状态,即 r 是 java.util.Random 的一个实例,还是只是一个 nooby 语法错误?
我只是在自己研究clojure,所以请多多包涵:)。
【问题讨论】:
感谢您包含整个堆栈跟踪。在这里它不是真的必要,但它可以提供巨大的帮助,而且人们通常不会打扰。 【参考方案1】:repeatedly
非常适合重复运行一个函数并将结果收集到一个序列中
user> (take 10 (repeatedly #(rand-int 42)))
(14 0 38 14 37 6 37 32 38 22)
至于您的原始方法:迭代接受一个参数,将其提供给一个函数,然后获取该结果并将其传递回同一个函数。我不是你想要的,因为你使用的函数不需要任何参数。您当然可以给它一个该参数的占位符并让它工作,尽管repeatedly
可能更合适。
(defn random-numbers [max]
(iterate (fn [ignored-arg] (.nextInt r max)) (.nextInt r max)))
#'user/random-numbers
user> (println (take 5 (random-numbers 10)))
(3 0 0 2 0)
【讨论】:
【参考方案2】:作为一般指南,不要从 Java 中的类/函数开始。首先看看 Clojure 的核心函数和在 clojure.* 中的命名空间(然后是在模块化存储库中贡献的命名空间:参见 http://dev.clojure.org/display/doc/Clojure+Contrib); rand-int 本身在 clojure-core 中很容易获得。那么,如何开始寻找随机数助手呢?
从 Clojure 1.3 开始,您可以“使用”clojure-repl 命名空间来访问方便的 apropos 函数(与 Unix/linux 中的 apropos 命令的使用精神相同); apropos 返回到目前为止加载的命名空间中所有匹配的定义。
user> (use 'clojure.repl)
nil
user> (apropos "rand")
(rand rand-int rand-nth)
clojure.repl 中的 find-doc 函数也是另一种选择。
另一个指针是在 www.clojuredocs.org 上搜索,其中包括 clojure core 和 clojure.* 中的函数的用法示例。
【讨论】:
【参考方案3】:至少出于测试目的,最好能够通过为生成器播种来重复“随机”序列。新的spec
库以这种方式报告其测试结果。
原生 Clojure 函数不允许您播种随机序列,因此我们必须求助于底层 Java 函数:
(defn random-int-seq
"Generates a reproducible sequence of 'random' integers (actually longs)
from an integer (long) seed. Supplies its own random seed if need be."
([] (random-int-seq (rand-int Integer/MAX_VALUE)))
([seed]
(let [gen (java.util.Random. seed)]
(repeatedly #(.nextLong gen)))))
【讨论】:
【参考方案4】:让我们用一个转换器吧?
(def xf (map (fn [x] (* 10 (rand)))))
我们也可以使用rand-int
作为:
(def xf (map (fn [x] (* 10 (rand-int 10)))))
要使用它来生成惰性序列,我们将使用sequence
(sequence xf (range))
这会返回一个惰性随机数序列。要获得 n 个数字的完整序列,我们可以使用 take
为:
(take n (sequence xf (range)))
【讨论】:
嗨!您能否解释一下变量[x]
在您的两个xf
定义中的作用?对我来说,它们似乎没有任何作用,xf
可能没有任何论据(即(def xf [] ...)
,但我是 Clojure 的新手,可能错过了一些值得学习的东西:-)
你传入映射的函数需要一个参数,以便它可以映射它。它让一切变得更容易,将其阅读为 fn [_]
代替 fn[x]
好的,否则,我们将(range)
的输出传递给我们的自定义函数,它不会对生成的值做任何事情,而是返回一个随机值;这很聪明。感谢您的澄清!以上是关于如何在clojure中创建一个惰性随机数序列的主要内容,如果未能解决你的问题,请参考以下文章