4

System.Random.MWC.Monadから Rand モナドを使用して無限の数のストリームを生成したいと思います。このモナドの MonadFix インスタンス、または次のようなインスタンスがある場合のみ:

instance (PrimMonad m) => MonadFix m where
     ...

次に、次のように書くことができます。

runWithSystemRandom (mfix (\ xs -> uniform >>= \x -> return (x:xs)))

しかし、1つもありません。

私はMonadFix のドキュメントを調べていましたが、このインスタンスを実装する明確な方法がわかりません。

4

3 に答える 3

6

MonadFix インスタンスを作成できます。ただし、コードは個別の乱数の無限ストリームを生成しません。mfix の引数は、1 回だけ呼び出す関数ですuniform。コードが実行されると、uniform一度だけ呼び出され、結果を含む無限リストが作成されます。

同等の IO コードを試して、何が起こるかを確認できます。

import System.Random
import Control.Monad.Fix
main = print . take 10 =<< mfix (\xs -> randomIO >>= (\x -> return (x : xs :: [Int])))

ステートフルな乱数ジェネレーターを使用し、ジェネレーターを実行してその結果を遅延収集したいようです。を慎重に使用しないと、それは不可能ですunsafePerformIO。多くの乱数をすばやく生成する必要がない限り、randomRs代わりに などの純粋な RNG 関数を使用できます。

于 2011-03-20T01:50:15.370 に答える
3

(これは、ヒートシンクの回答へのコメントとして適していますが、少し長すぎます。)

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

于 2014-09-14T07:32:51.870 に答える