もっと一般的ですが、あなたが望むものと一致するタイプの関数を定義することができます。
import System.Random
randoms' :: (RandomGen g, Random a) => g -> Int -> ([a], g)
randoms' g n =
let (g1, g2) = split g
in (take n $ randoms g1, g2)
がsplit
split :: g -> (g, g)
を使用していてもsplit
操作は、一つは、2つの別個の乱数発生器を得ることを可能にします。これは関数プログラム(例えば、乱数ジェネレータを再帰呼び出しに渡す)で非常に便利ですが、統計的に頑強な実装のsplit
&hellipについてはほとんど行われていません。
それでもあなたが望むことはしません。 (私は簡単視覚的な比較のために以下の実施例にBool
を使用。)
ghci> g <- getStdGen
ghci> randoms' g 5 :: ([Bool], StdGen)
([False,False,False,True,False],1648254783 2147483398)
ghci> randoms' g 5 :: ([Bool], StdGen)
([False,False,False,True,False],1648254783 2147483398)
メモランダムの配列が同じであること。
機能は発電機を分割する手間になりますが、速やかに廃棄します。代わりに、あなたのコードはIO
モナドで実行されている場合、あなたは
のように、最後にグローバル乱数生成器を置き換えるために
setStdGen
を使用することができます
ghci> let (a1,g2) = randoms' g 5 :: ([Bool], StdGen)
ghci> let (a2,_) = randoms' g2 5 :: ([Bool], StdGen)
ghci> (a1,a2)
([False,False,False,True,False],[True,True,True,False,True]
のように後続の呼び出しにそれを通すことによってg2
の使用を作ります
myAction :: Int -> IO ([Float],[Float])
myAction n = do
g <- getStdGen
let (f1,g2) = randoms' g n
let (f2,g3) = randoms' g2 n
setStdGen g3
return (f1, f2)
周囲のスレッド状態が扱いにくく、エラーを起こしやすい。多数の定型文がある場合は、State
またはST
を使用することを検討してください。
もう1つのオプションは、ジェネレータを2つに分割することです(http://hackage.haskell.org/packages/archive/random/latest/doc/html/System-Random.html#v:split)。その後、生成されたジェネレータの1つを使用して 'randoms'を呼び出し、もう一方のジェネレータを続行することができます。無限リストでも動作します。 – hammar