問題は、それMaybe
がトランス スタックの一部ではないことです。変圧器が と しか知らない場合、StateT Int
をIO
持ち上げる方法については何も知りませんMaybe
。
T
タイプを次のように変更することで、これを修正できます。
type T = StateT Int (MaybeT IO) Int
(インポートする必要がありますControl.Monad.Trans.Maybe
。)
ではなく、内部do
を使用するように変更する必要もあります。これは、生の値を次のようにラップすることを意味します。MaybeT
Maybe
Maybe a
MaybeT . 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
。