Életem első monádja

A monád fogalom megértésének útján eljutottam ahhoz az állomáshoz, amikor megírtam életem első monádját. Ez a monád álvéletlen számoktól függő eredményt reprezentál. Lehetséges, hogy ekvivalens valamelyik "gyári" monáddal, nem ismerem még mindegyiket.

A teszteléshez Monte Carlo elven működő pí-számolót csináltam. Íme a kód:

import System.IO
import System.Random

data Rnd g a = Rnd (g -> (a, g))

eval :: g -> Rnd g a -> (a, g)
eval g mv = (let Rnd f = mv in f g)

instance Monad (Rnd g) where
  (>>=) mv f = Rnd (\g -> let (x, g') = eval g mv in eval g' (f x))
  return x   = Rnd (\g -> (x, g))

monteCarlo :: (RandomGen g, Fractional a) => Rnd g a -> Int -> Rnd g a
monteCarlo sampler n = do
  samples <- sequence $ replicate n sampler
  return (sum samples / fromIntegral n)

estimatePi = monteCarlo randomSample
  where
    randomSample = do
      x <- (Rnd random :: RandomGen g => Rnd g Double)
      y <- (Rnd random :: RandomGen g => Rnd g Double)
      return ((if x*x + y*y < 1 then 4 else 0) :: Double)

main = do
    gen <- newStdGen
    putStr "n = "
    hFlush stdout
    num <- getLine
    print $ fst $ eval gen $ estimatePi (read num :: Int)

Hozzászólások

Nahát! Úgy tűnik éppen a State monádot találtam fel. :)

import System.IO
import System.Random
import Control.Monad.State

monteCarlo :: (RandomGen g, Fractional a) => State g a -> Int -> State g a
monteCarlo sampler n = do
  samples <- sequence $ replicate n sampler
  return (sum samples / fromIntegral n)

estimatePi = monteCarlo randomSample
  where
    randomSample = do
      x <- (state random :: RandomGen g => State g Double)
      y <- (state random :: RandomGen g => State g Double)
      return ((if x*x + y*y < 1 then 4 else 0) :: Double)

main = do
    gen <- newStdGen
    putStr "n = "
    hFlush stdout
    num <- getLine
    print $ fst $ runState (estimatePi (read num :: Int)) gen

Persze a C változat 50x gyorsabb, és ugyanilyen hosszú.


#include <stdio.h>
#include <stdlib.h>
#include <time.h>

int main(int argc, char *argv[])
{
	int i, n;
	double sum;

	srand(time(NULL));

	printf("n = ");
	scanf("%d", &n);

	sum = 0;
	for (i = 0; i < n; i++) {
		double x = (double) rand() / RAND_MAX;
		double y = (double) rand() / RAND_MAX;
		sum += (x*x + y*y < 1);
	}
	sum /= n;
	sum *= 4;

	printf("%g\n", sum);

	return EXIT_SUCCESS;
}

Mondjuk ebben nincs általánosan megírva a Monte Carlo, hanem csak egyben az egész feladat.