12

機能について学びましrandomた。

私の理解では、random関数は型のインスタンスである値を取り、値RandomGenを指定できるランダムな値を返します。一方、mksdGenを取り、関数が必要Intとする乱数発生器を生成しrandomます。

ランダムなBool値を生成しようとしていました。そのために、関数を作成しましたrandomBool

randomBool :: Int -> Bool
randomBool = fst . random . mkStdGen

それから、小さい数のTrues よりもはるかに多くの s を見つけました。Falseそして、私はそれについて興味があり、次のように確認しました

> length $ takeWhile randomBool [1..]
53667

random . mkStdGenこれは、最初の 53667 個の正の整数に対して が を返すことを意味すると思いますがTrue、これは私にはあまりランダムではないようです。ごく普通ですか?Trueそれとも、より簡単に起こる何か間違ったことをしていますか?

4

3 に答える 3

3

Computers are deterministic and can't generate random numbers. Rather, they rely on mathematical formulas that return a distribution of numbers that look random. These are called pseudo-random number generators. However, because of the determinism, we have the problem that if we ran these formulas the same way during each invocation of our program, we would get the same random number generators. Obviously, this is no good, since we want our numbers to be random! Thus, we have to provide the random generator an initial seed value that changes from run-to-run. For most people (i.e., those not doing cryptographical stuff), the random number generator is seeded by the current time. In Haskell, this pseudo-random generator is represented by the StdGen type. The mkStdGen関数は、シードを持つ乱数ジェネレーターを作成するために使用されます。グローバルな乱数ジェネレーターが 1 つある C とは異なり、Haskell では、いくつでも持つことができ、異なるシードを使用してそれらを作成できます。

ただし、注意点があります。数値は疑似乱数であるため、異なるシードで作成された乱数ジェネレーターが、他のシードと比較してランダムに見える数値を返すという保証はありません。これは、呼び出して連続するシード値を指定した場合、作成した から取得した数値が、後続のシード値と比較してランダムrandomBoolであるという保証がないことを意味します。これが、ほぼ 50000 を取得する理由です。StdGenStdGenTrue

実際にランダムに見えるデータを取得するには、同じ乱数ジェネレーターを引き続き使用する必要があります。お気付きのように、randomHaskell 関数には type がありStdGen -> (a, StdGen)ます。Haskell は純粋であるため、このrandom関数は乱数ジェネレータを取り、疑似乱数 (戻り値の最初の要素) をStdGen生成してから、元のシードでシードされたジェネレータを表す new を返しますが、新しい乱数を与える準備ができています。番号。ランダムなデータを取得するには、これを保持して次の関数にStdGen渡す必要があります。random

ab、およびの 3 つのランダムなブール値を生成する例を次に示しcます。

randomBools :: StdGen -> (Bool, Bool, Bool)
randomBools gen = let (a, gen') = random gen
                      (b, gen'') = random gen''
                      (c, gen''') = random gen'''
                   in (a, b, c)

random への呼び出しを通じて、変数がどのようにgen「スレッド化」されるかに注目してください。

You can simplify passing state by using a state monad. For example,

import Control.Monad.State
import System.Random

type MyRandomMonad a = State StdGen a

myRandom :: Random a => MyRandomMonad a
myRandom = do
  gen <- get -- Get the StdGen state from the monad
  let (nextValue, gen') = random gen -- Generate the number, and keep the new StdGen
  put gen' -- Update the StdGen in the monad so subsequent calls generate new random numbers
  return nextValue

Now you can write the randomBools function as:

randomBools' :: StdGen -> (Bool, Bool, Bool)
randomBools' gen = fst $ runState doGenerate gen
  where doGenerate = do
          a <- myRandom
          b <- myRandom
          c <- myRandom
          return (a, b, c)

If you want to generate a (finite) list of Bools, you can do

randomBoolList :: StdGen -> Int -> ([Bool], StdGen)
randomBoolList gen length = runState (replicateM length myRandom) gen

Notice how we return the StdGen as the second element of the returned pair, to allow it to be given to new functions.

More simply, if you just want to generate an infinite list of random values of the same type from an StdGen, you can use the randoms function. This has the signature (RandomGen g, Random a) => g -> [a]. To generate an infinite list of Bool using a starting seed of x, you simply run randoms (mkStdGen x). You can implement your example using length $ takeWhile id (randoms (mkStdGen x)). You should verify that you get different values for different initial values of x, but always the same value if you supply the same x.

最後に、モナドに縛られることを気にしないのであればIO、Haskell は命令型言語によく似たグローバルな乱数ジェネレーターも提供します。モナドで関数randomIOを呼び出すIOと、好きな型のランダムな値が得られます (Random少なくとも型クラスのインスタンスである限り)。モナドmyRandomを除いて、これは上記と同様に使用できます。IOこれには、Haskell ランタイムによって事前にシードされているという便利さが追加されています。つまり、StdGen. Boolしたがって、モナドで 10のランダムなリストを作成するには、次のIOようにします。replicateM 10 randomIO :: IO [Bool].

お役に立てれば :)

于 2013-06-25T19:02:10.857 に答える