Diagramsを使って円周率をモンテカルロ法で計算する

Using queries
Diagramsのqueryを使うと、点が図形の内部にあるか外部にあるかが判別できる。

> {-# LANGUAGE NoMonomorphismRestriction #-}
> 
> import System.Random
> import Data.Monoid
> import Control.Applicative
> import Diagrams.Prelude
> import Diagrams.Backend.Cairo.CmdLine
> 
> main = putStrLn . show $ calcPi points

`gens`は乱数のタプルのリストを作っている。何かもっといい方法はない?

> tmap f (a,b) = (f a, f b)
> gens = uncurry zip $ tmap randoms $ split . mkStdGen $ 100

`c`は半径1の円。

> c :: Diagram Cairo R2
> c = circle 1

`points`は乱数から生成された点のリスト。

> points = map p2 $ take 10000 $ gens

`sample c pt`で点`pt`が図形`c`の内部にあるかどうかが分かる。

> count p = length . filter (== Any True) $ sample c <$> p

`calcPi`で円周率の計算。(内部の点の個数) / (全部の点の個数) * 4

> calcPi p = (fromIntegral . count $ p) / (fromIntegral . length $ p) * 4

実行結果:

monte$ ghc monte.lhs
[1 of 1] Compiling Main             ( monte.lhs, monte.o )
Linking monte ...
monte$ ./monte 
3.146
monte$ 

(Haskell力が足りない……)