私はSystem.Random
ライブラリを使用しています。私は完全に理解していない動作を経験しました。以下のshuffle
機能は、Fischer-Yates shuffleの実装であり、置換えなしでランダムサンプルとしても機能します。例えば。 2.ランダムジェネレータの予期しない動作
import Control.Monad as M
import Control.Monad.ST
import Data.Vector.Unboxed as VU
import Data.Vector.Unboxed.Mutable as VUM
import System.Random
go = do
g <- newStdGen
let (rand_vec1, g1) = randVector 10 g
let (rand_vec2, g2) = randVector 10 g
let (rand_sample1, g3) = shuffle rand_vec1 2 g
let (rand_sample2, g4) = shuffle rand_vec1 2 g
print rand_vec1
print rand_vec2
print rand_sample1
print rand_sample2
randVector :: (RandomGen g) => Int -> g -> (VU.Vector Int, g)
randVector n = shuffle vector (VU.length vector) where
vector = VU.enumFromN 0 n
shuffle :: (RandomGen g, Unbox a) => VU.Vector a -> Int -> g -> (VU.Vector a, g)
shuffle li size g = runST $ do
vector <- VU.unsafeThaw li
let n = VUM.length vector - 1
let step g i = do
let (j,g') = randomR (0,n) g
VUM.swap vector i j
return g'
g' <- M.foldM step g [0..size-1]
v' <- VU.unsafeFreeze vector
let vec = VU.take size v'
return (vec, g')
リストおよびリストの長さとshuffle
を呼び出すと、リスト全体をシャッフルしますが、リストおよび数2でそれを呼び出すと、長さのランダムなサンプルを抽出する必要があり、私はrand_vec1
とrand_vec2
であることに気づきます同じ乱数発生器が使用されるので、常に同じであり、これは予想される。
しかし、両方とも同じランダムジェネレータを使用していても、rand_sample1
とrand_sample2
は異なります。見知らぬ人でも、時間の半分以上は、常にではありませんが、rand_sample2
は、(以下の例のように)サンプリングされるベクトルの2つの最初の番号を含んでいます。どうして? 出力例:
[3,0,4,9,7,2,1,8,5,6]
[3,0,4,9,7,2,1、 8,5,6]
[9,2]
[3,0]
(また、コードレビューが理解される)
明示的に返されない限り、 'runST'の変更は"エスケープ "できないと思いました。 'shuffle'は副作用がありません。なぜなら、すべてが' runST'の内部で行われるからです。 – tsorn
これが意味することの例を提示できれば助かります。ここでの問題は、STモナドの根底にある仮定に違反する安全でない操作を使用していることです。 – ErikR
それはそれを説明する! 'VU.unsafeThaw'を' VU.thaw'に変更することで、ランダムサンプルは等しくなります。私が 'runST'で安全でない操作を使用しないと、操作に副作用があってはいけませんよね? – tsorn