A ConTeXt style file for formatting RSS feeds for Kindle

As I said in the last post, I bought an Amazon Kindle Touch sometime back, and I find it very useful for reading on the bus/train while commuting to work.I use it read novels and books, a few newspapers and magazines that I subscribe to, and RSS feeds of different blogs that I follow. Until now, I had been using ifttt to send RSS feeds to Instapaper; Instapaper then emails a daily digest as an ebook to kindle account at midnight; in the morning, I switch on my Kindle for a minute; the Kindle syncs new content over Wifi; and off I go.

However, Kindle typesets ebooks very poorly,  so I decided to write a ConTeXt style file to typeset RSS feed (check it out on github).  To use this style:

\usemodule[rssfeed]

\starttext
\setvariables
    [rssfeed]
    [title={Title of the feed},
     description={Description of the feed},
     link={A link to the feed},
    ]

\starttitle[title={First feed entry}]
....
\stopttitle

\starttitle[title={Second feed entry}]
...
\stoptitle

\stoptext

It uses the eink module to set the page layout and fonts, and use a light and clean style for formatting feed entries. Since the proof is in the pudding, look at following PDFs to see the style for different types of blogs.

I use a simple ruby script to parse RSS feeds and uses Pandoc to convert the contents of each entry to ConTeXt. The script is without bells and whistles, and there is no site specific formatting of feeds. All feeds are handles the same way, and as a result, there are a few glitches: For example, IEEE uses some non-standard tags to denote math) which Pandoc doesn’t handle and the images generated by WordPress blogs that use $latex=...$ to typeset math are not handled correctly by ConTeXt, etc.

The script also uses Mutt to email the generated PDF to my Kindle account. This way, I can simply add a cron job that runs the script at appropriate frequency (daily for usual blogs, weekly for low traffic blogs, and once a month for table of contents of different journals).

Don’t complicate your code

A friend sent me a link to a blog post that discusses solutions to the Josephus problem in Perl, Ruby, and Python. Ouch! Those implementations hurt.

The Josephus problem is a simple discrete math puzzle:

Flavius Josephus was a roman historian of Jewish origin. During the Jewish-Roman wars of the first century AD, he was in a cave with fellow soldiers, 40 men in all, surrounded by enemy Roman troops. They decided to commit suicide by standing in a ring and counting off each third man. Each man so designated was to commit suicide…Josephus, not wanting to die, managed to place himself in the position of the last survivor.

In the general version of the problem, there are n soldiers numbered from 1 to n and each k-th soldier will be eliminated. The count starts from the first soldier. What is the number of the last survivor?

Keep reading

Programming in Maxima

Recently, in one of my papers I needed to do somewhat involved polynomial algebra. Basically, adding and substracting polynomials in p and 1-p with degree n. The calculations were relatively straight forward, but I always make silly mistakes with such calculations. So, I decided to check my analysis using a computer algebra system. Matlab and Mathematica, perhaps the most popular computer algebra softwares (although Matlab is focussed more on numerical calculations), were out of the picture because they are commercial and I did not have site licenses for them. So, I googled a bit and settled on Maxima.

To get started, I used wxMaxima, which provides a nice GUI for Maxima. wxMaxima makes learning maxima easy. It works as I expect an CAS IDE to work. After playing around the GUI for a while, I wanted to write a script to check my calculations. It turns out that writing a script is not that easy.

You can create a wxMaxima document, which is somewhat like a Mathematica notebook. The difference is that wxMaxima document is a text file, in fact a valid maxima file. Therefore, all the formatting information is stored in the comments. Here is an example:

/* [wxMaxima: comment start ]
In Proposition 1, we define a transformation $A_i$. Since we are only interested
in the symmetric arrival case, we only need to work with
   [wxMaxima: comment end   ] */

/* [wxMaxima: input   start ] */
Ap(n) := 1 - (1-p)^(n+1) ;
/* [wxMaxima: input   end   ] */

The display output in wxMaxima looks really nice. But, for some unexplainable reason, I can only think logically when I am editing text using vim. All the moving up and down in the wxMaxima window makes me lose my train of thought. Writing an elaborate markup so that wxMaxima pretty prints the comments was too cumbersome, so I needed to figure out how to write a script in maxima. (On second thoughts, maybe using the wxMaxima syntax was not too bad. But then, all progress is made by the unsatisfied man!)

Now, Maxima is meant to be an interactive program. So, it echos everything that it reads and it is not easy to distinguish the desired output from the rest. After a bit of digging into the manual, I found that ending a line with $ instead of ; does not show the output. However, if you read the file using batch, the input lines are still displayed, which is a bit annoying. After more digging around in the manual, I realized that I should be loading the file using batchload—which does not display input or output lines; only the output of print and display are shown. Unfortunately, maxima does not have a command line switch to batchload a file, but that can be overcome using --batch-string flag.

In short, if you are looking to use maxima as a normal programming language:

  1. End your lines with $ rather than ;
  2. Run the program using maxima --batch-string="batchload(\"filename\")$"

and be aware that maxima is meant for interactive use. For some functions, it uses asksign which requires explicit user intervention. Of course, there are workarounds.

Edit: Roman pointed out another neat trick; run your script as an initialization file using --init-mac. The only trouble is that init-mac is meant for initialization files, so after


maxima -q --init-mac=filename

you end up in interactive mode. To overcome that, either add an explicit quit(); at the end of your script, or add the options --batch-string="quit();".

Imitating Metapost using Haskell

Brent Yorgey has released a Haskell EDSL for creating diagrams. Here is my first impression of the library, comparing it with another DSL for creating diagrams — Metapost.

lineLets start with the simplest example: drawing a straight line between two points. First the metapost code

draw (0,0)--(100,100)
withpen pencircle scaled 4bp withcolor red;

Now the same code in Haskell (this needs to be wrapped around in a function and rendered to a png or pdf, but I’ll leave that part out).

lineColor red . lineWidth 4 .
  straight $ pathFromVectors [(0,0),(100,-100)]

I like the Metapost style better (since I have been using that for ages). One minor annoyance with diagrams is that positive values of y goes downwards rather than upwards. But the main trouble for me is prefix versus infix style. For diagrams, I find the infix style much easier to read. In this post, I will try to persuade Haskell to follow that style. The transforms in the diagram package have the signature Something -> Diagram -> Diagram, while I want Diagram -> Something -> Diagram. That is easy to fix

linecolor  = flip lineColor
linewidth  = flip lineWidth
fillcolor  = flip fillColor

Now we can use

straight (pathFromVectors [(0,0),(100,-100)])
  `linewidth` 4 `linecolor` red

circleNow lets try the next simplest example: drawing a circle. Again, the metapost code first

fill fullcircle scaled 100
withcolor 0.5green ;

draw fullcircle scaled 100
withpen pencircle scaled 3 withcolor 0.5blue ;

Now using the above flipped functions, we can draw this by (there is a minor difference in metapost and diagrams. Metapost draws a circle of  a given diameter while diagrams draws a circle of a given radius).

circle 50
  `linewidth` 3 `linecolor` lightblue `fillcolor` lightgreen

Ah, much better than the metapost version.

I need to figure out two more things to be able to use the diagrams package in my publications.

  • How to define the infix equivalents of metapost’s --, ---, .., and ... in Haskell.
  • Write a Metapost/ConTeXt backend to render text using TeX.

Here is the complete code

import Graphics.Rendering.Diagrams

linecolor  = flip lineColor
linewidth  = flip lineWidth
fillcolor  = flip fillColor

example1 =
straight (pathFromVectors [(0,0),(100,-100)]) `linewidth` 4 `linecolor` red

example2 =
circle 50 `linewidth` 3 `linecolor` lightblue `fillcolor` lightgreen

main = do
renderAs PNG "line.png" (Width 100) example1
renderAs PNG "circle.png" (Width 100) example2

Assertions in Haskell

Sometime back, I posted how to solve the Monty Hall problem with a million doors. Christophe Poucet wondered if I was making a mistake in my solution: maybe I was not ensuring that the host is not opening a door with a car. I did not think so, but then I have been wrong in the past.  So, I wanted to check my solution. First I thought of using QuickCheck to test if the host function was correct, but that would mean that I write a test property and then call it to check that everything was correct. And then make sure that there was no difference between the test and the main problem. But I am lazy, and wanted an easier solution. Enter the assert function from Control.Exception. I just made two changes in my previous program.

  1. I added a new import
    import Control.Exception (assert)
    
  2. I changed the randomVariable function to
    randomVariable :: (Door -> [Door] -> Door) -> MC Double
    randomVariable strategy = do
      u <- nature
      c <- contestant
      h <- host (options u c)
      let r = assert (all (\d -> open u d == Goat) h) $ reward u (strategy c h)
      return r
    

recompiled the code, and voila, no error messages. This means that my reasoning was correct. And now I can assert that my reasoning is correct. See GHC documentation and Haddock for more details on assertions.

Problem of Points using Monte Carlo

A Franciscan monk named Luca Paccioli wrote a book Summa de arithmetic, geometrica et proportionalitià in 1494, where is posed the now famous problem of points.

A and B are playing a fair game of balla. They agree to continue until one has won six rounds. The game actually stops when A has won five and B three. How should the stakes be divided.

This problem gave birth to modern probability theory. Read The Unfinished Game by Keith Devlin for a fascinating account of how Pascal and Fermat struggled to find a solution to this problem. In the book Devlin says

Interestingly, as far as we know, neither Pascal, Fermat, nor anyone else sought to resolve the issue empirically. If you were actually to play out the completion of the game many times— that is, imagine the game had been halted after eight tosses, with A ahead five to three, and then toss actual coins to complete the game—you would find that A wins roughly 7/8 of the time.

(I have reworded the above quote to match with the problem statement.)

Sounds like Devlin is asking us to verify the claim by Monte Carlo simulation. Lets do that.

import Control.Applicative ( (<$>) )
import Control.Monad.MC
import Text.Printf (printf)

Lets start by defining the game. We have two players

data Player = A | B deriving (Eq, Show)
players = [A,B]

Define a record to store the current state of the game.

data Game = Game { pointsA :: Int
                 , pointsB :: Int
                 , pointsTotal :: Int } deriving Show
game :: Game
game = Game 5 3 6

At any round, a player can win with equal probability. So,

play :: MC Player
play = sample 2 players

Lets create a sequence of tosses. Notice that the game must end after (pointsTotal - pointsA) + pointsTotal - pointsB) - 1 rounds.

tosses :: MC [Player]
tosses = sequence . replicate count $ play where
  count = (total - a) + (total - b) - 1
  total = pointsTotal game
  a     = pointsA     game
  b     = pointsB     game

We need to keep track of the current score of each player. I use a tuple to store the score, and use the following function to update the score.

updateScore :: (Int, Int) -> Player -> (Int, Int)
updateScore (a,b) A = (a+1,b)
updateScore (a,b) B = (a, b+1)

Next I define a function that keeps track of the score as the game progresses.

scores :: MC [(Int,Int)]
scores = scanl updateScore (a,b) <$> tosses where
  a = pointsA game
  b = pointsB game

Given a sequence of scores,  I can determine who won the game.

winner :: [(Int, Int)] -> Player
winner []         = error "Calculating winner of an empty sequence"
winner ((a,b) : xs) | a >= total  = A
                    | b >= total  = B
                    | otherwise   = winner xs
  where
      total = pointsTotal game

Now, we need to compute the probability that A wins the game. Since, I am using a Monte Carlo simulation, I need a random variable to keep track of the number of times player A has won. This can be done by simply assigning a reward of 1 when player A wins and a reward of 0 when player 2 wins. That way, the expected value of the reward will be equal to the probability that A wins.

reward :: Player -> Double
reward A = 1
reward B = 0

And finally, the Monte Carlo simulation.

main :: IO ()
main = let
  n     = 1000000
  seed  = 101
  stats = repeatMC n (reward <$> winner <$> scores) `evalMC` mt19937 seed
  in do
      printf "Probability that A wins : %f\n" (sampleMean stats)
      printf "99%% Confidence interval : (%f, %f)\n"
               `uncurry` (sampleCI 0.99 stats)

This gives

Probability that A wins : 0.8749600000000389
99% Confidence interval : (0.8741080072900288, 0.8758119927100491)

The actual solution of the problem is 7/8=0.875. So, the problem would have been resolved much earlier had the Renascence mathematician had access to Monte Carlo simulations 🙂

The tale of two tiling WMs

I love tinkering with my system. About a year ago, I got this crazy idea of trying different window managers (WM). Until then, I had mostly used GNOME and occasionally explored KDE. Before that I was a happy Windows XP users (that means, I did not know what I WM was!). After trying XFCE and a couple of *boxes, I came across tiling window managers. The first one that I tried was wmii (actually wmii-ruby), which I found to be very nifty. At that time, I was gung-ho about ruby, and was elated to use a WM based on ruby. After a while, I found wmii-ruby to be a bit slow. The reason the wmii was slow was ruby. The bare bones wmii was amazingly fast. So, I switched to it. But wmii is that it is very poorly documented and uses an arcane language to configure (plan9!!). It is a struggle to figure out how to change anything. There are ruby, phython, and perl ports, but then you have to deal with the idiosyncrasy of the  port.

These days I am gung-ho about Haskell. What luck then that Haskell has a tiling window manager — XMonad. Whenever I feel frustrated with wmii, I check out XMonad. It is developing at an amazing pace, is well documented (well, if you know how to read Haskell documentation) and comes with an awful lot of addons called xmonad-contrib. However, everytime I try XMonad, after a while I switch back to wmii.

After repeating this process for the n-th time, I decided to write down what is wrong with XMonad.  The major inconvenience is the tags and the key bindings. In wmii, you can have as many alpha-numeric tags as you want. In XMonad, you have nine numeic tags. With alphanumeric tags, I can name the tags based on what project I have on them, and I do not need to remember it. I look at the tag name and I know which project is there. With XMonad, things are a bit different. Tags 1 and 2 are easy (mail and browser), but tags after that are a mess. What happens when I start a project on tag 3, start another on 4, and another on 5. After a week, the first project is over. I remove everything from tag 3, and reuse it. After three weeks, I need to carry the state of all my tags in my head. It is agonizing. And usually that  is the time when I switch back to wmii. I wish XMonad would implement named tags correctly. Which means, I do not have to change my config file and recompile xmoand to change the names of my tags!

My second gripe with XMonad is that its window management model does not fit my work model (rather the work model that I have gotten used to while using wmii). Most of the time, I am either writing a paper in tex, or writing code in haskell. In both cases, I have the screen split vertically. When working on a paper, I have two xterms on the left: one with vim displaying the tex file, and the other for compiling the file. On the right side,  I have three-four pdfs open (for reference), with the column in stack mode, so that I can read the title of the pdf file. The situation is similar while coding in haskell. Vim with Haskell code on one side, ghci on the other. Another xterm for compiling the code. And a couple of browser windows for checking the documentation. So, I work in a two column mode, with two main windows: the editor and the typeset pdf, or the editor and the debugger. XMonad’s philosophy is having one main window.  That is really irritating to me. There are user packages that allows you to split the screen in two columns, where I can achieve something similar to stacked mode in each column, but the key bindings are horrible (I mean, I might as well use Emacs).

I love XMonad, especially the new prompt and integration with xmobar. And I really like hacking around in Haskell to configure my WM. But, XMonad comes in the way. And after fighting with it for a while, I realize that there is nothing really wrong with wmii. And I switch back to wmii. I hope XMonad will implement proper named tags and a true two column layout sometime in the future.

Haskell on Arch Linux

I was a happy user of Ubuntu until a few months ago when GHC 6.10 was released. Ubuntu still had GHC 6.8.2. Posts on haskell-cafe told that Arch Linux had support for latest GHC, and support for over 700 Haskell libraries. Since I had started using Haskell for a few projects, I decided ot check Arch linux out. After a long weekend of struggling through the installation and learning more about linux than I intended to know, I had all my usual programs up and running on Arch. Once I discovered AUR, I had the latest versions of almost everything. Or so I thought.

The first glitch was that Arch does not install the profiling version of the libraries. I asked around on #haskell, and I was told, that I should use cabal to install the profiling version of libraries. I did not want to have conflicting versions of libraries, so I uninstalled a few libs from the Arch repositories, and manually installed them using cabal.

And now I figured out that Haskell libraries are not so up-to-date on AUR. For example, new versions of monte-carlo and gsl-random were released more than a week ago, but AUR still has the old versions. So, I decided to install them using cabal.

After having used Arch for about two months, I am not convinced that it has a good support for Haskell. The only good thing is that it comes with a version of cabal that can upgrade itself. (From what I remember, the ubuntu version of cabal could not upgrade  itself, and I had to install cabal by hand). But once cabal is updated, it is much more convenient to use cabal than the Arch repositories. Arch is a great distribution and I  like the rolling release philosophy, but its support for Haskell is mediocre at best.

Most programming languages come with their own tools for installing libraries (CPAN for perl, gem for ruby, cabal for Haskell, and now even texlive has a tool for updating packages). I do not think that it is worth the effort to port packages to distribution repositories. Simply using the language’s tool for installing libraries is much simpler and much easier to maintain.

Monty Hall with a billion doors

In order to provide intuition behind the solution of the Monty Hall problem, Antonio Cangiano says:

If there were a billion doors, you picked one, and then Monty proceeded to open up all the remaining doors but one, we’d have a situation where it would be extremely unlikely that you picked the right door at the beginning, while it would be extremely likely that the remaining door was the one that was concealing the car.

Now, what happens when there are more than three doors. In this post, I will modify the solution of my last post to work for any number of doors. It requires a little change to the program.

 import Data.List (delete, (\\) )
 import Text.Printf (printf)
 import Control.Monad
 import Control.Monad.MC

This time, instead of defining Door by listing all alternatives, I define it as an instance of Bounded class.

 data Door   = Door Int deriving (Show, Eq)
 numDoors    = 3

 instance Bounded Door where
   minBound = Door 1
   maxBound = Door numDoors

 instance Enum Door where
   toEnum      n     = Door n
   fromEnum (Door n) =    n

 doors = [minBound .. maxBound] :: [Door]

Object are the same as before.

 data Object = Car | Goat deriving (Show, Eq)
 type Universe = [Object]

There is one car; all other doors have goats. This can still be generated using the shuffle function.

 nature :: MC Universe
 nature = shuffle numDoors (Car: repeat Goat)

The contestant open one door at random.

 contestant :: MC Door
 contestant = sample numDoors doors

The options available to the host remain the same as before.

 options :: Universe -> Door -> [Door]
 options universe door = filter (\d -> Goat == open universe d) remainder
   where remainder = delete door doors

We need a generic function to see what is behind a closed door.

 open :: Universe -> Door -> Object
 open universe (Door n) = universe !! (n-1)

The host opens all but one door. We can do this by replacing the sample function with sampleSubset function.

 host :: [Door]-> MC [Door]
 host o = sampleSubset (numDoors-2) l o where l = length o

The strategies are now whether to stick or switch based on the door that the contestant chose, and the doors that the host opened.

 strategyStick :: Door -> [Door] -> Door
 strategyStick d1 d2 = d1

 strategySwitch :: Door -> [Door] -> Door
 strategySwitch d1 d2 = head (doors \\ (d1:d2))

The reward function is same as before.

 reward :: Universe -> Door -> Double
 reward u d = if Car == open u d then 1.0 else 0.0

And so is the generation of the ranom experiment.

 randomVariable :: (Door -> [Door] -> Door) -> MC Double
 randomVariable strategy = do
   u <- nature
   c <- contestant
   h <- host (options u c)
   let r = reward u (strategy c h)
   return r

And we see the result.

 main = let
   n     = 100000
   seed  = 42
   stats = repeatMC n (randomVariable strategyStick) `evalMC` mt19937 seed
   in do
      putStrLn $ printf "\nnumDoors                : %d" numDoors
      putStrLn $ printf "Mean                    : %f" (sampleMean stats)
      putStrLn $ printf "99%% Confidence interval : (%f, %f)"
                `uncurry` (sampleCI 0.99 stats)

Now lets see the results. For

numDoors                : 3
Mean                    : 0.3334800000000033
99% Confidence interval : (0.3296397390134338, 0.33732026098657275)

numDoors                : 30
Mean                    : 0.03466999999999957
99% Confidence interval : (0.03317983597888913, 0.03616016402111001)

numDoors                : 300
Mean                    : 0.0038399999999999784
99% Confidence interval : (0.0033362101507491866, 0.00434378984925077)

Well, I think that you get the idea. I am not going to run this thing for a billion doors.

Monty Hall problem using Monte Carlo simulations

n0ne showed how to translate Monte Carlo simulations of the Monty Hall Problem from Ruby and Python to Haskell. Since I have been trying to understand Patrick Perry’s monte-carlo monad, I thought that this is a good problem to start with. Monty Hall problems is one of those probability problems where the result is opposite to what intuition suggests.

Lets start by importing some Haskell packages that I will use later on. The most important for our purpose is Control.Monad.MC, which provides a nice wrapper to do Monte Carlo simulations.

 import Data.List (delete, (\\) )
 import Text.Printf (printf)
 import Control.Monad
 import Control.Monad.MC

So, the Monty Hall problem goes as follows. A contestant in game show faces three doors. There is a car behind one of them and goats behind the other two. He picks a door, and then the game show host, who knows what is behind the doors, opens one of the other doors to reveal a goat. The contestant then has the option to stick to his original choice, or switch to the unopened door. What is better?

One thing that I like about Haskell is its expressiveness. In particular, one can translate each line above from English to Haskell and get a working example. Let see.

  • A contestant in a game show faces three doors.
    data Door = Door1 | Door1 ">Door2 | Door3 deriving (Show, Eq, Enum)
    doors = [Door1 .. Door3]
    
  • There is a car behind one of them and goats behind the other two.
    data Object = Car | Goat deriving (Show, Eq)
    type Universe = [Object]
    
    nature :: MC Universe
    nature = shuffle 3 [Car, Goat, Goat]
    

Here shuffle is a function from monte-carlo package, which as the name suggests shuffles the first three objects from [Car, Goat, Goat]. This represents our state of the world.

  • He picks a door
    contestant :: MC Door
    contestant = sample 3 doors

The function sample is also from monte-carlo package. It picks one out of the list of options.

  • and then the game show host, who knows what is behind the doors, opens one of the other doors to reveal a goat.

Lets break down each English phrase. First, we need to figure out what options the game show host has. He can open any door which has a goat behind it. So, first we figure out which of the remaining doors have a goat behind them.

 options :: Universe -> Door -> [Door]
 options universe door = filter (\d -> Goat == open universe d) remainder
   where remainder = delete door doors

 open :: Universe -> Door -> Object
 open [a,_,_] Door1 = a
 open [_,a,_] Door2 = a
 open [_,_,a] Door3 = a
 open _        _    = error "Wrong number of elements in the universe"

Now the host can pick any one of the them.

 host :: [Door]-> MC Door
 host o = sample (length o) o where
  • The contestant then has the option to stick to his original choice, or switch to the unopened door.

I will write a function for each strategy of the contestant, even though one function is redundant.

 strategyStick :: Door -> Door -> Door
 strategyStick d1 ">d2 ">d1 d2 = d1
strategyFlip :: Door -> Door -> Door
 strategyFlip d1 d2 = head (doors \\ [d1,d2])
  • What is better?

Ah, the finale. Assuming that the contestant wants a car over a goat, we need to associate a reward with the outcome. If the outcome is a Car, the contest gets a reward of 1 Car, otherwise he gets 0 Cars.

 reward :: Universe -> Door -> Double
 reward u d = if Car == open u d then 1.0 else 0.0

Now, which strategy gives the contestant a better reward on average. We can, of course evaluate the average reward of each strategy analytically. We can also use the probability monad by Martin Erwig, which does exact probability calculations in Haskell. It even has Monty Hall problem as one of the examples. In this post, however, I am interested in a Monte Carlo approach. Monte Carlo approach works on the law of large numbers: one can approximate the expected value of a random variable by taking independent samples from its distribution and computing the sample average. To do so in Haskell, I first need to define the random variable, which in this case is the reward that we get. We need to specify the strategy in order to determine the outcome.

 randomVariable :: (Door -> Door -> Door) -> MC Double
randomVariable strategy = do
   u <- nature
   c <- contestant
   h <- host (options u c)
   let r = reward u (strategy c h)
   return r

This function says that the outcome is produced as follows. First nature chooses the ordering of the objects behind the door, then the contestant chooses a door, then the host opens a door, and then, depending on the contestant’s strategy, he gets a reward.

This is another good thing about Haskell. I can switch to an imperative style whenever it is convenient. In this case I can sequence a bunch of random events, and I have not even talked about generating random number!. Haskell provides a complete separation of generating random variable from the Monte Carlo simulation. Thanks to the new repeatMC function in the monte-carlo package, running a simulation is straight-forward.

 main = let
   n     = 100000
   seed  = 42
   stats = repeatMC n (randomVariable strategyStick) `evalMC` mt19937 seed
   in do
putStrLn $ printf "Mean                    : %f" (sampleMean stats)
      putStrLn $ printf "99%% Confidence interval : (%f, %f)"
                `uncurry` (sampleCI 0.99 stats)

The results of the simulation are stored in the Summary data type, which I talked about in the last post.

I only output the result of the stick strategy. The result of the switch strategy is going to be (1 - result of stick), since if the contestant did not get the car by sticking to his choice, he would have gotten it by switching. And the result (surprise, surprise, if you did not know about Monty Hall problem)

Mean                    : 0.3355999999999993
99% Confidence interval : (0.33175368331333815, 0.3394463166866604)

So, sticking to one’s choice only wins 1/3rd of the time. Which means that switching wins 2/3rd of the time. So, if you happen to be in a Monty Hall game show—switch.