Randoms

date:28/02/2013

1. 概要

  1. Haskell で 乱数っぽいのを作る方法のメモ
  2. 参照透明性があるので、IO を使う
  3. System.Random のことだけ書いている

2. random とその仲間

乱数のために、 System.Random でいくつかの関数が用意されています。
乱数ジェネレータについては、後述。

2.1. random, randoms

  • random: 乱数ジェネレータとを受け取って、乱数と新しい乱数ジェネレータを返す
  • randoms: 乱数ジェネレータとを受け取って、乱数列を返す
random :: (RandomGen g, Random a) => g -> (a, g)
randoms :: RandomGen g => g -> [a]

2.2. randomR, randomRs

  • randomR: random の返す乱数値の範囲を制限したバージョン
  • randomRs: randoms の返す各乱数値の範囲を制限したバージョン
randomR :: RandomGen g => (a,  a) -> g -> (a,  g)
randomRs :: RandomGen g => (a,  a) -> g -> [a]

2.3. randomIO, randomRIO

  • randomIO: random において、グローバル乱数ジェネレータを使うようにしたもの
  • randomRIO: randomR において、グローバル乱数ジェネレータを使うようにしたもの
randomIO :: IO a
randomRIO :: (a,  a) -> IO a

3. 乱数ジェネレータ

ここからは、 上記の乱数ジェネレータを生成する方法についてメモしています。
大きく分けて、最初の乱数ジェネレータの生成方法は2つあります。
一旦乱数ジェネレータを生成できれば、上記の random(R) などを使うことで、
返り値として新しい乱数ジェネレータを得ることができ、次々と random(R) を呼ぶことで、擬似乱数を生成できます。

3.1 mkStdGen : Int を指定して、生成する

Int の値を受け取って、乱数ジェネレータを返します。
最初に選ぶ Int 値自体を変更することで、異なる乱数ジェネレータを得ることができ、
複数の乱数列が必要なときなどに重宝します。
mkStdGen :: Int -> StdGen

3.2 getStdGen : グローバル乱数ジェネレータを使う

グローバル乱数ジェネレータと呼ばれるものを使いましょう。
これは単一のジェネレータで、IOモナドによって管理されています。
グローバル乱数ジェネレータを更新する関数として、newStdGen が用意されています。
グローバル乱数ジェネレータを分割(split)して, 一方を返り値にして、もう片方で、グローバル乱数ジェネレータを更新しています。
getStdGen :: IO StdGen
newStdGen :: IO StdGen

ここまでの内容で、基本的な擬似乱数生成ができるようになりました。

4. まとめ

  1. Haskell で擬似乱数を扱うための最小限のことを書いた。
  2. こういうものにも モナドは役立っているらしい。