蒙蒂·霍尔(Monty Hall)和惰性序列(?)

时间:2019-03-03 23:58:05

标签: clojure functional-programming statistics

我刚刚开始学习Clojure,并且试图模拟Monty Hall问题:

(defn create-contest
  "Creates a monty hall doors contest"
  [n]
  (do (def door-with-car (rand-int n))
      (map
       (fn [i] (if (= i door-with-car) :car :closed))
       (range n)))) 

(defn create-doors
  "Create a collection of monty hall contests"
  [doors contests]
  (doall
   (map
     (fn [i] (create-contest i))
     (repeat contests doors))))

但是每次我执行create-doors功能时,所有装有轿厢的车门最终都处在相同的位置:

broker.core> (create-doors 4 10)
((:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed)
 (:car :closed :closed :closed))
broker.core> (create-doors 4 10)
((:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed))
broker.core> (create-doors 4 10)
((:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed))

我在做什么错了?

2 个答案:

答案 0 :(得分:6)

您非常接近,您应该在这里使用let而不是def形式:

(defn create-contest
  "Creates a monty hall doors contest"
  [n]
  (let [door-with-car (rand-int n)] ;; let instead of def
    (map
      (fn [i] (if (= i door-with-car) :car :closed))
      (range n))))

def会将一些值绑定到当前名称空间中的var,但是您想在此函数的范围内绑定一个值,这就是let的优点。另请参见this Q&A

(defn create-doors
  "Create a collection of monty hall contests"
  [doors contests]
  (map
    create-contest ;; no need to wrap create-contest in another function here
    (repeat contests doors)))

您不需要将create-contest包装在另一个与map一起使用的函数中-您只需将函数作为值直接传递给map即可。 doall仅用于强制实现map中的惰性序列,因此您可能不需要/想要在create-doors中使用它。

(create-doors 4 10)
=>
((:closed :closed :car :closed)
 (:closed :closed :closed :car)
 (:closed :car :closed :closed)
 (:closed :closed :closed :car)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :car :closed :closed)
 (:closed :closed :closed :car)
 (:closed :closed :car :closed)
 (:closed :closed :car :closed))

答案 1 :(得分:1)

@TaylorWood's solution开始,您可以更简洁地表示两个函数,尽管我不确定简洁版本是否清晰。

您的create-contest的{​​{1}}函数对每个数字map进行测试,以查看它是否是那个。最好直接更改一个。为此,我们需要一个向量,我认为您在模拟游戏时仍要查找该向量:

i

您的 (defn create-contest [n] (assoc (vec (repeat n :closed)) (rand-int n) :car)) 函数反复将相同的参数传递给其create-doors的函数。您可以在闭包上使用repeatedly以获得相同的效果:

map

(defn create-doors [doors contests]
  (repeatedly contests (partial create-contest doors)))