2

2 つのモナド アクションを構成する関数があるとします。

co :: Monad m => m a -> m a -> m a

co2 つのモナド アクションが互いに協力してタスクを完了する方法を説明する高階関数と考えることができます。

しかし今、最初のモナド アクションはモナド トランスフォーマー内にラップされている可能性があることがわかりましたが、2 番目のアクションはそうではありません。

one :: (MonadTrans t, Monad m) => t m a

two :: Monad m => m a

しかし、それらを一緒に構成したいので、関数が必要です:

co' :: (MonadTrans t, Monad m) => t m a -> m a -> t m a

そのため、すべてのプリミティブを context に持ち上げるだけで、最初のものt m aと連携できます。m amt

ここでのコツは、 orcoの実装をよく知らずにビルドすることです。答えは MFunctor パッケージのどこかにあるような気がします。実際、昨日も同様の質問がありました。しかし、何か良いことを思いつくことができませんか?mt

4

3 に答える 3

2

簡単な定義

t mこれを機能させるには、モナドのインスタンスが 必要です。

import Control.Monad
import Control.Monad.Trans

co :: Monad m => m a -> m a -> m a
co = undefined

co' :: (MonadTrans t, Monad m, Monad (t m)) => t m a -> m a -> t m a
co' one two = lift . flip co two . return  =<< one

問題に対する別の見方

liftパッケージからの定義を見ると、transformers似たようなものが欲しいので、答えを見つけるのに役立ちます

lift . return = return
lift (m >>= f) = lift m >>= (lift . f)

あなたが持っていてflip co one :: Monad m => m a -> m a、それを持ち上げて type の関数を取得したいのと同じように(MonadTrans t, Monad m, Monad (t m)) => t m a -> t m a。だからリフトの足跡をたどって

lift' :: (MonadTrans t, Monad m, Monad (t m)) => (m a -> m a) -> t m a -> t m a
lift' f tma = tma >>= (lift . f . return)

定義co'は簡単です

co' one two = lift' (flip co two) one

問題

上記のソリューションは型を満たしているだけですが、セマンティクスも満たしていますか? 問題を確認するためcoに、最初のアクションを見ずに常に 2 番目のアクションを返す関数を考えてみましょう。上記co'は、何かを決定する前に常に最初のアクションを実行するため、これを行うことはできません。したがって、最初のアクションの副作用は、 では発生しco'ませんが、 で発生しcoます。

一般解は存在するか?

ないと思います。実際にその関数を一般的に実装したいのは、 のような関数であり、実際に の副作用を実行せずにアクションt m a -> (m a -> m b) -> t m bを取得する必要があるためです。m at m am a

したがって、mIOモナドであり、tが何らかの状態を持つ State トランスフォーマーであり、oneアクションが実際にミサイルを発射し、その成功または失敗に応じて が変更されるとしStateます。ここで、ミサイルを発射せずに状態を実際に変更する必要があります。一般に、それは不可能です。

coどのアクションが最初に実行されるかなどの情報がわかっている場合はco'、上記の方法を使用して実装できます。

于 2013-08-22T19:35:11.443 に答える