[Haskell-cafe] St. Petersburg Game

Luke Palmer lrpalmer at gmail.com
Tue Nov 27 08:56:16 EST 2007

On Nov 27, 2007 1:27 PM,  <manolo at austrohungaro.com> wrote:
> Hello,
> I'm trying to program an implementation of the St. Petersburg game in
> Haskell. There is a coin toss implied, and the random-number generation is
> driving me quite mad. So far, I've tried this:

Yeah, random number generation is one of those things in Haskell that
can be tricky.  But it looks like you're struggling more with the idea
of monadic programming.  That is expected :-)

> import Random
> increment :: Int -> Int
> increment b = b + 1

This is unnecessary; it can just be written (+1).  (I.e. wherever you
said "increment" you could write "(+1)" instead)

> main =  do      let b = 0
>                 let c = randomRIO (1,2)
>                 until (c == 1)  increment b
>                 return b

You can think of this block as four "statements", one after the other.
 the "do-until" thing doesn't delimit anything, i.e. doesn't work the
way you think it does.   Let me rewrite this so it's clearer what's
going on:

main = do { let b = 0;
            let c = randomRIO (1,2);
            until (c == 1) increment b;
            return b;

In particular, until is a function, and you've given it three
arguments: c == 1 (which is False), increment, and b.

To solve this problem you'll probably want to use recursion, since it
is a loop.  There are "higher-order" ways to loop, but they all boil
down to recursion in the end.

So let's write a function which does this, call it count:

count :: Int -> IO Int

That is the type.  It takes an integer representing the current count,
does some IO and returns an integer.  Specifically, it should take the
current count and flip a coin.  If the coin comes up tails, it should
just return the current count.  It it comes up heads, it should call
itself again with 1 + the current count as an argument.  I'll get you

count currentCount = do
    coin <- randomRIO (1,2)

We use <- to run an action and get its result; we use let .. = to
define the meaning of a symbol (but nothing is run).  Using let just
gives a shorter name for an expression.

Why don't you try to write the rest?  main will look like:

main = do
    flips <- count 0
    print flips

I also recommend going through a tutorial which others will doubtless
recommend to you until you get to monads (or skip ahead to monads and
see if you understand).


More information about the Haskell-Cafe mailing list