>From http://en.wikipedia.org/wiki/Monty_Hall_problem we have this
description of the Monty Hall Problem:

> Suppose you're on a game show and you're given the choice of three
> doors [and will win what is behind the chosen door]. Behind one
> door is a car; behind the others, goats [unwanted booby prizes].
> The car and the goats were placed randomly behind the doors before
> the show. The rules of the game show are as follows: After you have
> chosen a door, the door remains closed for the time being. The game
> show host, Monty Hall, who knows what is behind the doors, now has
> to open one of the two remaining doors, and the door he opens must
> have a goat behind it. If both remaining doors have goats behind
> them, he chooses one [uniformly] at random. After Monty Hall opens
> a door with a goat, he will ask you to decide whether you want to
> stay with your first choice or to switch to the last remaining
> door. Imagine that you chose Door 1 and the host opens Door 3,
> which has a goat. He then asks you "Do you want to switch to Door
> Number 2?" Is it to your advantage to change your choice?

This Clojure code simulates the Monty Hall problem in an interesting
way: the monty-hall function is passed a contestant function that,
when invoked, a) picks a door at random and b) also returns a function
that re-decides which door to open after Monty opens one of the other
two and gives them the chance to switch (monty-hall does this by
calling that function with the number of the door Monty opened).

Two contestant functions are provided. Both make a uniformly random
initial choice of door. The staying-contestant returns a function that
will make the same choice of door after Monty opens one of the other
two. The switching-contestant will switch to the other unopened door.

The monty-avg function takes a contestant and a number of trials, has
that contestant play that many games, and returns the proportion of
times that contestant won. Example output for 10,000 trials is
included; some people may find the results counterintuitive, but the
math says that the results I got are exactly what they should be (and
that 1000 PhDs were wrong about that).

The code is idiomatic Clojure, using sequence functions in preference
to loop/recur and itself using higher order functions in what might be
described as a continuation-passing style. There is also no mutation
or impure function use except for the calls to rand-int and that rng's
hidden internal state; it could be made fully pure by passing around
an extra parameter in the form of a seq of random bits supplied
externally and, from functions that consume from the seq, returning
the reduced seq.

(defn rand-elt [seq]
  (nth seq (rand-int (count seq))))

(defn make-monty []
   (rand-elt
     [[:car :goat :goat]
      [:goat :car :goat]
      [:goat :goat :car]]))

(defn monty-hall [contestant]
  (let [m (make-monty)
        [door response-fn] (contestant)
        other-bad-doors (remove #(= (m %) :car)
                           (remove #(= % door)
                             [0 1 2]))
        wrong-door (rand-elt other-bad-doors)
        final-door (response-fn wrong-door)]
    (m final-door)))

(defn staying-contestant []
  (let [initial-door (rand-int 3)]
    [initial-door
     (constantly initial-door)]))

(defn switching-contestant []
  (let [initial-door (rand-int 3)]
    [initial-door
     (fn [wrong-door]
       (first
         (remove #(= % initial-door)
           (remove #(= % wrong-door)
             [0 1 2]))))]))

(defn monty-avg [contestant n-trials]
  (double
    (/
      (count
        (filter #(= :car %)
          (repeatedly n-trials #(monty-hall contestant))))
      n-trials)))

user=> (monty-avg staying-contestant 10000)
0.3362
user=> (monty-avg switching-contestant 10000)
0.6616

-- 
You received this message because you are subscribed to the Google
Groups "Clojure" group.
To post to this group, send email to clojure@googlegroups.com
Note that posts from new members are moderated - please be patient with your 
first post.
To unsubscribe from this group, send email to
clojure+unsubscr...@googlegroups.com
For more options, visit this group at
http://groups.google.com/group/clojure?hl=en

Reply via email to