2011-07-06 17 views
9

混乱しやすい質問の混乱のタイトル!私は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の出番

答えて

17

これは、それがで作業することができbar多型何モナドで行います。ページの下部にあるインスタンスのリストがMonadContのインスタンスが一度に知られていることを示していること

bar :: MonadCont m => Int -> m Int 
bar m = return $ m * 2 

注意生成されたドキュメントにはCont rMonad m => ContT r mの両方が含まれています。さらに、MonadContクラスは、継続機能を使用するために必要なものであるcallCC関数を定義するものです。つまり、bar内の連続の完全な表現を使用できますが、この例では使用できません。

このように、MonadIO制約を持たないため、またタイプが明示的にIOと指定されていないため、IOを使用できないことが明らかになっている関数を記述します。しかし、それらは、モナドが内部で働く多形であり、IOを含む文脈から自明に呼び出すことができる。

+1

ありがとうございました。それは動作します。私は私の望むものを私に与えてくれた私自身の解決策も見つけました(私は 'Bar'を変更する必要はありませんでした):' liftCont :: Cont(m r)a - > ContT r m a'; 'liftCont c = ContT $ runCont c'です。私のソリューションは 'Cont'を解凍し、' ContT'を構築します。私はあなたの解決策は、それが多型であり、データ構造の実際の操作を必要としないのでより良いと思います。しかし、私は 'bar'を変更できない場合に役立つので、私は別の答えとして投稿します。また、 'bar'でIOを使用することが不可能な理由については、+1してください。 – mgiuca

5

私はこれは私が(Barを変更せずに)望んでいたまさにないことが判明:

liftCont :: Cont (m r) a -> ContT r m a 
liftCont = ContT . runCont 

これはContをアンパックしContTを構築します。

私はその後、BarFooから呼び出すことliftContを使用することができます。私は、これはカールのソリューションよりも「よりよい」ではないと思います

foo n = do 
    let x = n + 1 
    liftIO $ print x 
    liftCont $ bar x 

(私は彼にダニを与えた)、私はそれので、それをここに投稿しましたタイプを変更せずにBarを使用できます。Barを変更できない場合は便利です。 (これはおそらくかかわらず、悪化した性能を持っています。)

関連する問題