質問

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 そして、単一の値を無期限に繰り返すだけです。

ライセンス: CC-BY-SA帰属
所属していません StackOverflow
scroll top