問題は、それMaybeがトランス スタックの一部ではないことです。変圧器が と しか知らない場合、StateT IntをIO持ち上げる方法については何も知りませんMaybe。
Tタイプを次のように変更することで、これを修正できます。
type T = StateT Int (MaybeT IO) Int
(インポートする必要がありますControl.Monad.Trans.Maybe。)
ではなく、内部doを使用するように変更する必要もあります。これは、生の値を次のようにラップすることを意味します。MaybeTMaybeMaybe aMaybeT . return
f :: T
f = do
x <- get
val <- lift $ do
val <- MaybeT $ return someMaybe
-- more code in Maybe monad
return 4
return 3
これは少し厄介なので、おそらく次のような関数を書きたいと思うでしょうliftMaybe:
liftMaybe = MaybeT . return
liftコードの他の部分で値を持ち上げていた場合IO a、現在はトランスフォーマー スタックに 3 つのレベルがあるため、これは壊れます。次のようなエラーが表示されます。
Couldn't match expected type `MaybeT IO t0'
with actual type `IO String'
これを修正するにはliftIO、すべての生のIO a値に使用する必要があります。これは、型クラスを使用して、IO任意の数の変換レイヤーを介してアクションを実行します。
あなたのコメントに応えて: に依存するコードが少ししかない場合は、表記の結果を変数に入れてそれと照合するMaybe方が簡単です:do
let maybeVal = do val <- someMaybe
-- more Maybe code
return 4
case maybeVal of
Just res -> ...
Nothing -> ...
これは、Maybeコードが IO を実行できないことを意味します。fromMaybeの代わりに のような関数を自然に使用することもできますcase。