混乱しやすい質問の混乱のタイトル!私はa)モナド、b)IOモナド、c)Contモナド(Control.Monad.Cont)、およびd)ContT連続変圧器モナドを理解する。 (モナド変圧器全般については漠然と理解していますが、この質問に答えるには十分ではありません)。すべての機能がContモナド(Cont r a
)にあるプログラムを書く方法を理解しています。 すべて関数は、Cont/IOモナド(ContT r IO a
)を組み合わせたものです。継続モナド内のIOモナドからの脱出
しかし、私はいくつかの機能を組み合わせ続き/ IOモナド(ContT r IO a
)にあり、他の機能は、単に続きモナド(Cont r a
)にあるプログラムを書くかもしれませんどのように思ったんだけど。基本的には、プログラム全体を継続的に書いていますが、必要に応じてI/Oモナドを使用します(通常のハスケルコードと同じように、IOモナドは必要な場合のみ使用します)。例えば
は、非継続スタイルで、この2つの機能を考慮してください。
foo :: Int -> IO Int
foo n = do
let x = n + 1
print x
return $ bar x
bar :: Int -> Int
bar m = m * 2
注foo
はIOが必要ですが、bar
が純粋であること。今、私は完全に継続モナドを使用してこのコードを作成する方法を考え出したが、私は同様にbar
を通じてIOスレッドのに必要な:
foo :: Int -> ContT r IO Int
foo n = do
let x = n + 1
liftIO $ print x
bar x
bar :: Int -> ContT r IO Int
bar m = return $ m * 2
「私は継続スタイルですべての私のコードをしたいですかが、私はドンtは、IOモナドを必要としない関数でIOモナドを使用する必要があります。基本的に、私はこのようなbar
を定義するためにをしたいと思います:
bar :: Int -> Cont r Int
bar m = return $ m * 2
残念ながら、私はContT r IO a
モナド機能(foo
)内部からCont r a
モナド関数(bar
)をコールする方法を見つけることができません。変換されていないモナドを変形されたモナドに「持ち上げる」方法はありますか?つまり、foo
の行「bar x
」を正しく変更してbar :: Int -> Cont r Int
を呼び出すにはどうすればよいですか? Control.Monad.Classの出番
ありがとうございました。それは動作します。私は私の望むものを私に与えてくれた私自身の解決策も見つけました(私は 'Bar'を変更する必要はありませんでした):' liftCont :: Cont(m r)a - > ContT r m a'; 'liftCont c = ContT $ runCont c'です。私のソリューションは 'Cont'を解凍し、' ContT'を構築します。私はあなたの解決策は、それが多型であり、データ構造の実際の操作を必要としないのでより良いと思います。しかし、私は 'bar'を変更できない場合に役立つので、私は別の答えとして投稿します。また、 'bar'でIOを使用することが不可能な理由については、+1してください。 – mgiuca