2017-07-07 2 views
1

これはもう少し長くなるはずです。mtl、reader、exceptt&stacking order

calledFunction 
    :: (MonadReader env m, HasToken env, MonadIO m) 
    => m (Either MyError MyResult) 

calledFunction2 
    :: (MonadReader env m, HasToken env, MonadIO m) 
    => m (Either MyError MyResult2) 
:良いニュースは、私は質問の下部のコードサンプルを持っていること、考えはちょうどそれが

&エレガントな:-)を構築することですされた私のようなシグネチャを持つ関数のカップルを持っています

そして最後に、ExceptT String IO MyResult3の結果を得たいと思っています。MyResult & MyResult2のようになります。

ExceptT :: m (Either e a) -> ExceptT e m a 

そして私はちょうどEitherT calledFunctionを入力し、私はもうm (Either MyError MyResult)が、ストレートExceptT MyError m MyResult)を持っていません。

は、今では私が活用できるのでcalledFunctionEitherを返すことは非常にうれしいです。進捗!

しかし、私はまた、calledFunctionに必要な読者のコンテキストを与える必要があります。さて、私はrunReaderTでそれを行うだろう。私は今... ..だから、ExceptT MyError (ReaderT Config IO) MyResultmがどこにあるので、当然ReaderTは行くべき、ExceptT MyError m MyResultトランススタックになってきた

それはだから、私はどのように、読むための値でreaderT「に記入」を除き

変圧器スタックの底部にありますか?私はトップレベルで読者を持つようにスタックを逆にあれば、そのrunReaderTは自然に来るが、私は私のエレガントExceptTEither ...

import Control.Monad.Reader 
import Control.Monad.Trans.Reader 
import Control.Monad.Trans.Except 
import Control.Monad.IO.Class 
import Control.Error -- 'error' package 

class HasToken a where 
    getToken :: a -> String 
data Config = Config String 
instance HasToken Config where 
    getToken (Config x) = x 

data MyError = MyError String deriving Show 
data MyResult = MyResult String 
data MyResult2 = MyResult2 String 

data MyResult3 = MyResult3 MyResult MyResult2 

calledFunction 
    :: (MonadReader env m, HasToken env, MonadIO m) 
    => m (Either MyError MyResult) 
calledFunction = undefined 

calledFunction2 
    :: (MonadReader env m, HasToken env, MonadIO m) 
    => m (Either MyError MyResult2) 
calledFunction2 = undefined 

cfg = Config "test" 

main = undefined 

test :: ExceptT MyError IO MyResult3 
test = do 
    -- calling runReaderT each time defeats the purpose.. 
    r1 <- ExceptT (runReaderT calledFunction cfg) 
    r2 <- ExceptT (runReaderT calledFunction2 cfg) 
    return $ MyResult3 r1 r2 

test1 = runReaderT test2 cfg 

test2 :: ReaderT Config (ExceptT MyError IO) MyResult3 
test2 = do 
    -- how to make this compile? 
    let cfg = Config "test" 
    r1 <- ExceptT calledFunction 
    r2 <- ExceptT calledFunction2 
    return $ MyResult3 r1 r2 

答えて

3

あなたが使用することができます変換するEitherTを使用する方法が表示されませんExceptT以下Readerを実行するためのControl.Monad.Morphからhoist

ghci> let foo = undefined :: ExceptT() (ReaderT() IO)() 
ghci> :t hoist (flip runReaderT()) foo 
hoist (flip runReaderT()) foo :: ExceptT() IO() 

それはまたそれを自分で行うのは簡単だ、あなただけの、runExceptTとアンラップする必要がrunReaderと環境を提供し、再

ghci> :t \env -> ExceptT . flip runReaderT env . runExceptT 
\env -> ExceptT . flip runReaderT env . runExceptT 
    :: r -> ExceptT e (ReaderT r m) a -> ExceptT e m a 
+0

右に、これは動作します:ExceptTコンストラクタで結果をラップ 'テスト=ホイスト(フリップrunReaderTのCFG)$やります...'。ありがとうございました! –