私は独自のモナドProducer
を使用して、ランダム性に依存する値を作成するを持っています:Random
policies :: Producer (Policy s a) Random x
Random
またはmwc-random
から実行できるラッパーです。ST
IO
newtype Random a =
Random (forall m. PrimMonad m => Gen (PrimState m) -> m a)
runIO :: Random a -> IO a
runIO (Random r) = MWC.withSystemRandom (r @ IO)
プロデューサーはpolicies
、単純な強化学習アルゴリズムから、ますます優れたポリシーを生成します。
にインデックスを付けることで、たとえば 5,000,000 回の反復後にポリシーを効率的にプロットできますpolicies
。
Just convergedPolicy <- Random.runIO $ Pipes.index 5000000 policies
plotPolicy convergedPolicy "policy.svg"
ここで、500,000 ステップごとに中間ポリシーをプロットして、それらがどのように収束するかを確認したいと考えています。プロデューサーを使用して、たとえば 10 個のポリシー (500,000 回の反復ごとに 1 つ) のpolicies
リスト ( ) を抽出し、それらすべてをプロットする関数をいくつか作成しました。[Policy s a]
ただし、これらの関数は、学習反復の合計回数が同じ (つまり 5,000,000) であっても、上記のように最終ポリシーをプロットするよりもはるかに時間がかかり (10 倍)、多くのメモリ (4 倍) を使用します。これは、ガベージ コレクターを禁止するリストを抽出したためではないかと考えています。
慣用的なパイプ スタイルでは、すべての要素をメモリにロードするのではなく、要素が生成されるとすぐに要素を消費します。
Producer
がランダムなモナド (つまりRandom
) の上にあり、生成したい効果が にある場合、このようなパイプを消費する正しいアプローチは何IO
ですか?
別の言い方をすれば、 aProducer (Policy s a) Random x
を aに接続したいのですConsumer (Policy s a) IO x
。