ランダム性
ランダム値を扱う。 Haskell は参照透明性を持つので関数が同じ引数で2回呼ばれた場合、 必ず同じ値を返すようになっていなければならない。 その中でランダム値をどのように作るのかを見る。
System.Random モジュールに random という関数があるので見ゆ
*Main Lib> :t random <interactive>:1:1: error: Variable not in scope: random *Main Lib> import System.Random <no location info>: error: Could not find module ‘System.Random’ It is a member of the hidden package ‘random-1.1@random-1.1-9tceXaeYIMZ4JrKq20Egog’.
めっちゃ怒られる
my-project.cabal
を編集
executable my-project-exe hs-source-dirs: app main-is: Main.hs ghc-options: -threaded -rtsopts -with-rtsopts=-N build-depends: base , my-project , random <= 追加 default-language: Haskell2010
stack に対して依存パッケージを指定してあげないとダメな模様
再度チャレンジ
*Main Lib> import System.Random *Main Lib System.Random> :t random random :: (RandomGen g, Random a) => g -> (a, g)
いけた。
RandomGen
型クラスはランダム性の源として扱える型を表現Random
型クラスはランダムな値になることができる型を表現
乱数ジェネレータを受け取り、ランダムな値と新しい乱数ジェネレータを返す
乱数ジェネレータが欲しい。 System.Random に StdGen という型がある。 これは RandomGen のインスタンスになっている。
*Main Lib System.Random> :i RandomGen class RandomGen g where next :: g -> (Int, g) genRange :: g -> (Int, Int) split :: g -> (g, g) {-# MINIMAL next, split #-} -- Defined in ‘System.Random’ instance RandomGen StdGen -- Defined in ‘System.Random’
乱数ジェネレータを自分で作るには mkStdGen 関数を使う。
*Main Lib System.Random> :t mkStdGen mkStdGen :: Int -> StdGen
整数を引数にとってその値を元に乱数ジェネレータを返す。
ランダム値を作ってみる
*Main Lib System.Random> random (mkStdGen 100) :: (Int, StdGen) (-3633736515773289454,693699796 2103410263) *Main Lib System.Random> random (mkStdGen 100) :: (Int, StdGen) (-3633736515773289454,693699796 2103410263) *Main Lib System.Random> random (mkStdGen 223344) :: (Int, StdGen) (-262505389206341605,1147014161 2103410263)
タプルの1番目の値がランダム値、2番目が新しい乱数ジェネレータの数値としての表現。 同じ乱数ジェネレータを渡すと同じ値が返ってくる。
型注釈をつけることで、Int 以外のランダム値を得ることができる。
*Main Lib System.Random> random (mkStdGen 100) :: (Bool, StdGen) (True,4041414 40692) *Main Lib System.Random> random (mkStdGen 100) :: (Float, StdGen) (0.6512469,651872571 1655838864) *Main Lib System.Random> random (mkStdGen 100) :: (Integer, StdGen) (-3633736515773289454,693699796 2103410263)
コイントス
3回のコイントスをシミュレートする関数を書く
import System.Random threeCoins :: StdGen -> (Bool, Bool, Bool) threeCoins gen = let (firstCoin, newGen) = random gen (secondCoin, newGen') = random newGen (thirdCoin, newGen'') = random newGen' in (firstCoin, secondCoin, thirdCoin)
実行
*Main System.Random> threeCoins (mkStdGen 100) (True,False,False) *Main System.Random> threeCoins (mkStdGen 200) (True,False,True) *Main System.Random> threeCoins (mkStdGen 300) (True,True,True)
random gen で *Coin の値が 型注釈無しで Bool 値になるのは、 関数の型宣言に書いてあるため、Haskellが型推論できるから。
所感
他の言語でもランダム値の生成については今まであまり触れてこなかったので、 Haskell でどのように乱数が生成されるのかを知れて良かった。
あと、let めっちゃかっこよく使っててすごい。
(参考)
https://qiita.com/katsuyan/items/a132d7bf6817f19af2d6

- 作者: MiranLipovaca
- 出版社/メーカー: オーム社
- 発売日: 2017/07/14
- メディア: Kindle版
- 購入: 4人 クリック: 9回
- この商品を含むブログを見る