18

私は数日Haskellをいじっていて、問題に遭遇しました。

整数のランダムリストを返すメソッドが必要です(Rand [[Int]])。

そこで、タイプを定義しました:type Rand a = StdGen -> (a, StdGen)。なんとかRand IO IntegerしてRand [IO Integer]( )制作できました。(returnR lst) :: StdGen -> ([IO Integer], StdGen)制作のヒントはありますRand [[Int]]か?

4

4 に答える 4

21

回避する方法IOは、そもそもなぜ導入されているのかによって異なります。疑似乱数ジェネレーターは本質的に状態指向ですが、IO関与する必要はありません。

推測して、最初のPRNGを使用しているnewStdGenか取得していると言います。getStdGenその場合、完全に脱出する方法はありませんIO。代わりに、を使用してPRNGを直接シードすることもできますmkStdGen。同じシードを使用すると、同じ「乱数」シーケンスが生成されることに注意してください。

より可能性が高いのは、内部でPRNGを取得しIO、それを純粋関数への引数として渡すことです。もちろん、すべては最後にラップさIOれますが、中間の計算では必要ありません。これがあなたにアイデアを与えるための簡単な例です:

import System.Random

type Rand a = StdGen -> (a, StdGen)

getPRNG = do
    rng <- newStdGen
    let x = usePRNG rng
    print x

usePRNG :: StdGen -> [[Int]]
usePRNG rng = let (x, rng') = randomInts 5 rng
                  (y, _) = randomInts 10 rng'
              in [x, y]

randomInts :: Int -> Rand [Int]
randomInts 0 rng = ([], rng)
randomInts n rng = let (x, rng') = next rng
                       (xs, rng'') = randomInts (n - 1) rng'
                   in (x:xs, rng'')

現在の値を絶えず前後に渡すため、PRNGを使用するコードがかなり醜くなることに気付くかもしれません。また、古い値を誤って再利用する可能性があるため、エラーが発生しやすい可能性もあります。上記のように、同じPRNG値を使用すると、同じ数列が得られますが、これは通常、必要なものではありません。どちらの問題も、モナドを使用することが理にかなっていることを示す完璧な例です。ここでStateは話題から外れていますが、次に調べてみることをお勧めします。

于 2010-04-29T16:01:23.510 に答える
11

HackageでMonadRandomを再作成しています。これが実行できるかどうかを確認するための単なる実験ではない場合は、代わりにそのライブラリを使用することをお勧めします。

于 2010-04-29T23:17:34.593 に答える
6

の無限のリストを取得したい場合は、値を取り戻すIntegerことができないため、問題が発生します。StdGenここで実行したいのはsplitStdGen最初の半分をもう一度渡し、残りの半分を「使い切って」整数の無限リストを生成することです。このようなもの:

infiniteRandomInts :: Rand [Int]
infiniteRandomInts g = (ints, g2) where
    (g1,g2) = split g
    ints = randoms g1

ただし、このアプローチを繰り返してsの無限行列Integer(を使用して必要と思われる)を取得すると、統計的な性質の問題が発生する可能性があります。繰り返しのtingをRand [[Int]]どれだけうまく処理できるかわかりません。の別の実装の方が良いかもしれません。あるいは、ある種の斜めの歩行を使用して、をに変換することもできます。StdGensplitRandomGen[Int][[Int]]

于 2010-04-29T20:47:33.710 に答える
3

モナディック表記を使用すると、次のようなものを書くことができるはずです

randomList gen = do
    randomLength <- yourRandomInteger
    loop gen (randomLength + 1)
 where
    loop gen 1 = gen
    loop gen n = do { x <- gen; xs <- loop gen (n - 1); return (x:xs) }

そしてこれで

randomInts :: Rand [Int]
randomInts = randomList yourRandomInteger

randomLists :: Rand [[Int]]
randomLists = randomList randomInts

モナディック計算自体については、この記事をご覧ください。IOランダムジェネレーターは純粋であることに注意してください。この目的のためだけにジェネレーターは必要ありません。

于 2010-04-29T15:36:07.397 に答える