6

次のコードがあります。

import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.State

type T = StateT Int IO Int

someMaybe = Just 3

f :: T
f = do
    x <- get
    val <- lift $ do
        val <- someMaybe
        -- more code in Maybe monad
        -- return 4
    return 3

do内部で記法を使用してMaybeモナドで作業すると失敗します。doエラーから、これの型シグネチャが一致しないように見えます。しかし、私はそれを修正する方法がわかりません。いくつかの組み合わせを試しliftましたが、どれも機能せず、もう推測したくありません。

4

2 に答える 2

8

問題は、それMaybeがトランス スタックの一部ではないことです。変圧器が と しか知らない場合、StateT IntIO持ち上げる方法については何も知りません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

于 2013-04-17T15:35:52.827 に答える
3

doコードを純粋にモナド内で実行したい場合は、またはモナドMaybeにアクセスできません(これは良いことかもしれません)。そうすることで値が返されるので、精査する必要があります。StateT IntIOMaybe

import Control.Monad
import Control.Monad.Trans
import Control.Monad.Trans.State

type T = StateT Int IO Int

someMaybe = Just 3

f :: T
f = do
    x <- get
    -- no need to use bind
    let mval = do
        -- this code is purely in the Maybe monad
        val <- someMaybe
        -- more code in Maybe monad
        return 4
    -- scrutinize the resulting Maybe value now we are back in the StateT monad
    case mval of
        Just val -> liftIO . putStrLn $ "I got " ++ show val
        Nothing -> liftIO . putStrLn $ "I got a rock"
    return 3
于 2013-04-17T15:55:46.137 に答える