人気ブログランキング | 話題のタグを見る

Random モジュールの使い方

寄り道ついでに Random モジュールも覗いてみた。乱数はゲームを作ったり、シミュレーションをしたりするときに必須なので、Haskell での作り方を知っておいて損はない。

ghci で乱数を試すときは、まず Random モジュールをインポートする必要がある。
Prelude> :m Random
Prelude Random>


乱数はシード値という数値を元に、演算で作成する。Haskell の場合デフォルトのシード値があり、getStdGen で取り出すことができる。
Prelude Random> getStdGen
486513661 1


このシード値を元に乱数を発生させるわけだが、それには、getStdRandom 関数を使う、この関数は引数に random 関数または randomR 関数をとり乱数を発生させることができる。シード値は暗黙に利用されるので引数には現れない。

getStdRandom 関数が random 関数を引数に取ると、範囲指定のない整数値の乱数を発生させる。
Prelude Random> getStdRandom random
-134536735
Prelude Random> getStdRandom random
-929791202


getStdRandom 関数が randomR 関数を引数にとると、範囲指定のある乱数を発生させることができる。randomR 関数は数値のペアを引数にできるが、整数値のペアの場合乱数は整数値が発生する。
Prelude Random> getStdRandom (randomR (1, 6))
1
Prelude Random> getStdRandom (randomR (1, 6))
3


randomR 関数の引数が実数値のペアの場合、実数値の乱数を getStdRandom 関数で発生させることができる。
Prelude Random> getStdRandom (randomR (0.0, 1.0))
0.6565188367749841
Prelude Random> getStdRandom (randomR (0.0, 1.0))
0.5448677856579581


また、乱数の無限リストを発生させる関数があり、randoms は範囲指定のない乱数の無限リストを、randomRs は範囲指定のある乱数の無限リストを発生させる。

randoms は引数にシード値をとる。シード値は getStdGen で取得することができるが、getStdGen の戻値は IO モナド型なので、そのままでは使えない。シード値を取り込む関数を1引数IO a型戻値の IO モナド型関数にしておいて、>>= 演算子で注ぎ込まないといけない。
Prelude Random> getStdGen >>= return . (take 3) . randoms
[-1346026573,-1375852214,106540112]


あるいは、do 記法をつかうと、もう少し分かりやすいかもしれない。
Prelude Random> do rand <- getStdGen; return (take 3 (randoms rand))
[-1346026573,-1375852214,106540112]


同様に randomRs を使って範囲指定のある乱数のリストを発生させるには次のようにする。
Prelude Random> getStdGen >>= return . (take 3) . (randomRs (1, 6))
[6,4,1]
Prelude Random> do rand <- getStdGen; return (take 3 (randomRs (1, 6) rand))
[6,4,1]


シード値を変更したい時は newStdGen 関数を使う。
Prelude Random> newStdGen
429156803 1336516155
Prelude Random> newStdGen
429196817 498340276
Prelude Random> newStdGen >>= return . (take 3) . (randomRs (1, 6))
[1,6,2]


これで乱数の作り方は分かったが、作成された乱数は IO a 型で戻されるのでそのままでは使えない。乱数を利用する方も1引数 IO a 型戻値の IO モナド型関数にしなければならないので注意が必要だ。

サイコロを振って3より大きければ勝ちで、3以下なら負けとなるプログラムを作ってみよう。最初は do 記法で。
Prelude Random> do score <- getStdRandom (randomR (1, 6)); return (if score > 3 then "you win" else "you loose")
"you loose"


>>= 演算子を使うとこうなる。
Prelude Random> getStdRandom (randomR (1, 6)) >>= return . (\x -> if x > 3 then "you win" else "you loose")
"you loose"


どうやっても、負けてしまった。
by tnomura9 | 2011-08-17 19:46 | Haskell | Comments(0)
<< Data.List モジュール... System.Time モジュ... >>