[Haskell-beginners] PI calculation - Newbie question

Felipe Lessa felipe.lessa at gmail.com
Fri Jan 29 07:32:08 EST 2010

On Fri, Jan 29, 2010 at 12:59:30PM +0200, Gabi wrote:
> I think the problem is in  "rs <- sequence (replicate n isRandIn)"  -
> But I don't know how to get around it (how do I get a lazy sequence of
> rs? Is it the problem anyway?)

First of all, we don't like to be inside IO just for getting
random numbers.  It is better to write, for example,

  type Point = (Double, Double)

  randPoint :: StdGen -> (Point, StdGen)
  randPoint gen = let (x, gen')  = randomR (0,1) gen
                      (y, gen'') = randomR (0,1) gen'
                  in ((x,y),gen'')

and then thread the generator yourself

  randPoints :: StdGen -> [Point]
  randPoints gen = let (p,gen') = randPoint gen
                   in p : randPoints gen' -- lazy!

To use those functions, something like

  import Control.Applicative ((<$>))

  inCirc :: Point -> Bool
  inCirc = ...

  calcPi :: Int -> [Point] -> Double
  calcPi n pts = let s = length $ filter inCirc $ take n pts
                 in 4 * fromIntegral s / fromIntegral n

  main = do pi <- calcPi 10000 . randPoints <$> newStdGen
            print pi

I haven't tested performance, but it shouldn't be worse :), and
it's cleaner and more idiomatic.  To be even clearer you could
use MonadRandom[1] which encapsulates the passing of StdGen between

[1] http://hackage.haskell.org/package/MonadRandom

However System.Random (used by MonadRandom as well) is known to
be very very very very slow.  If you want more performance then
you should use one of the other PRNG libraries on Hackage:


The reason why System.Random is slow is because it must support
'split', which none of the packages above support.



More information about the Beginners mailing list