ランドモナドのMonadfixインスタンス
質問
Rand Monadで数字の無限のストリームを生成したい System.random.mwc.monad. 。このモナドにはモナドフィックスインスタンスがある場合、またはこのようなインスタンスがある場合
instance (PrimMonad m) => MonadFix m where
...
その後、書くことができます:
runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))
しかし、それはありません。
私は経験していました Monadfixドキュメント しかし、私はこのインスタンスを実装する明白な方法を見ていません。
解決
質問:最初の種子をどのように生成したいですか?
問題は、MWSがIOとStrict(Control.monad.st.st.st)のみを抽象化する「プリミティブ」パッケージに基づいて構築されていることです。抽象的なlazy(control.monad.st.lazy.st)も抽象的ではありません。
おそらく、「プリミティブ」がレイジーSTをカバーするためのインスタンスを作ることができ、MWSは怠zyになる可能性があります。
更新:control.monad.st.lazyを使用してこの作業を作成できます。
module Main where
import Control.Monad(replicateM)
import qualified Control.Monad.ST as S
import qualified Control.Monad.ST.Lazy as L
import qualified System.Random.MWC as A
foo :: Int -> L.ST s [Int]
foo i = do rest <- foo $! succ i
return (i:rest)
splam :: A.Gen s -> S.ST s Int
splam = A.uniformR (0,100)
getS :: Int -> S.ST s [Int]
getS n = do gen <- A.create
replicateM n (splam gen)
getL :: Int -> L.ST s [Int]
getL n = do gen <- createLazy
replicateM n (L.strictToLazyST (splam gen))
createLazy :: L.ST s (A.Gen s)
createLazy = L.strictToLazyST A.create
makeLots :: A.Gen s -> L.ST s [Int]
makeLots gen = do x <- L.strictToLazyST (A.uniformR (0,100) gen)
rest <- makeLots gen
return (x:rest)
main = do
print (S.runST (getS 8))
print (L.runST (getL 8))
let inf = L.runST (foo 0) :: [Int]
print (take 10 inf)
let inf3 = L.runST (createLazy >>= makeLots) :: [Int]
print (take 10 inf3)
他のヒント
Monadfixインスタンスを書くことができます。ただし、コードは異なる乱数の無限のストリームを生成しません。 MFIXへの引数は、呼び出す関数です uniform
一度だけ。コードが実行されると、呼び出されます uniform
一度、結果を含む無限のリストを作成します。
同等のIOコードを試して、何が起こるかを確認できます。
import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))
ステートフルな乱数ジェネレーターを使用したいと思うようで、ジェネレーターを実行して結果を怠zileに収集したいと考えています。それは慎重に使用せずに不可能です unsafePerformIO
. 。多くの乱数を迅速に生成する必要がない限り、次のような純粋なRNG関数を使用できます randomRs
代わりは。
(これは、ヒートシンクの答えへのコメントとしてより適していますが、少し長すぎます。)
MonadFix
インスタンスは接着する必要があります いくつかの法律. 。それらの1つはです 左縮小/泥棒:
mfix (\x -> a >>= \y -> f x y) = a >>= \y -> mfix (\x -> f x y)
この法律により、表現を書き直すことができます
mfix (\xs -> uniform >>= \x -> return (x:xs))
= uniform >>= \x -> mfix (\xs -> return (x:xs))
= uniform >>= \x -> mfix (return . (x :))
別の法律を使用して、 純度 mfix (return . h) = return (fix h)
, 、さらに簡素化できます
= uniform >>= \x -> return (fix (x :))
標準的なモナド法と書き換えを使用します fix (x :)
なので repeat x
= liftM (\x -> fix (x :)) uniform
= liftM repeat uniform
したがって、結果は実際に1つの呼び出しです uniform
そして、単一の値を無期限に繰り返すだけです。