2013-04-17 11 views
6

のスタック内のモナド。このエラーのため、このタイプの署名のように見えます。これはdoと一致しません。しかし、私はそれをどのように修正するか分かりません。私はいくつかliftの組み合わせを試しましたが、それらのどれも働いていませんし、もう推測したくありません。は、たぶん私は、次のコードを持っている変圧器

+0

:そうすることであなたは精査する必要がありますMaybe値を返しますStateT Int'と 'IO'もそうですか? – pat

+0

'Maybe'モナドのみ。 – Adrian

答えて

8

問題はMaybeがトランススタックの一部ではないという点です。変圧器がStateT IntIOしか知っていない場合は、Maybeを持ち上げる方法については何も知られていません。あなたが好きなものにあなたのタイプTを変更することでこの問題を解決することができ

type T = StateT Int (MaybeT IO) Int 

(あなたはControl.Monad.Trans.Maybeをインポートする必要があります。)

またで動作するようにあなたの内側のdoを変更する必要がありますMaybeではなくMaybeTです。これはMaybeT . returnで生Maybe a値をラップ意味:

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 

あなたが他にIO a値を持ち上げるためにliftを使用した場合あなたのコードの一部を削除します。なぜなら、今あなたのトランススタックに3つのレベルがあるからです。

Couldn't match expected type `MaybeT IO t0' 
      with actual type `IO String' 

これを修正するには、すべてのあなたの生IO aの値についてliftIOを使用する必要があります:あなたはこのようになりますエラーが発生します。これは、任意の数のトランスレイヤーを介して動作するために、タイプメッシュを使用します(IO)。あなたのコメントを受けて

let maybeVal = do val <- someMaybe 
        -- more Maybe code 
        return 4 
case maybeVal of 
    Just res -> ... 
    Nothing -> ... 

:あなただけMaybeに応じて、コードのビットを持っている場合、ちょうどそれに対する変数と試合do表記の結果を置くために容易になるだろうつまり、コードMaybeはIOを実行できません。また、caseの代わりにfromMaybeのような機能を使用することもできます。あなたは純粋にMaybeモナドにおける内doでコードを実行したい場合は

+0

私はこのモナドで動作するたくさんの関数を持っていますが、それらのうちの1つでは、 'Maybe'からいくつかの値をアンパックする必要があり、' do'表記を使用するとネストされた 'case' expereionを取り除くことができます。タイプを定義することはこれを行う唯一の方法ですか? – Adrian

+0

もちろん、 'MaybeT'トランスを使用するブロックに対して' runMaybeT'を使うこともできます。 – dflemstr

+0

@Adrian: 'do'表記をそれ自身の関数に抽出して、それと一致する単一のcase式を持つことができます。実際、これがおそらく最善のアプローチです。しかし、あなたはモナド変圧器をもっと理解するために私のバージョンでちょっと遊んでください。 –

3

、あなたは(良いことかもしれません)StateT IntまたはIOモナドにアクセスすることはできません。あなたが唯一の `Maybe`モナドで実行するためのインナー` do`にコードをしたいか、またはそれは `にアクセスする必要があるん

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 
関連する問題