我無法抓住monads和monad變壓器。我有 以下人爲的例子(未編譯):monad在monad變壓器上下文
import Control.Monad
import Control.Monad.Error
import Control.Monad.Reader
data State = State Int Int Int
type Foo = ReaderT State IO
readEither :: String -> Either String Int
readEither s = let p = reads s
in case p of
[] -> throwError "Could not parse"
[(a, _)] -> return a
readEitherT :: IO (Either String Int)
readEitherT = let p s = reads s
in runErrorT $ do
l <- liftIO (getLine)
readEither l
foo :: Foo Int
foo = do
d <- liftIO $ readEitherT
case d of
Right dd -> return dd
Left em -> do
liftIO $ putStrLn em
return (-1)
bar :: Foo String
bar = do
liftIO $ getLine
defaultS = State 0 0 0
如果我複製readEither到readEitherT的功能,它的工作原理,但我 有一種揮之不去的感覺,我可以充分利用現有的 readEither的力量功能,但我無法弄清楚如何。如果我嘗試解除readEitherT函數中的 readEither,它會將其解除爲應有的ErrorT String IO (Either String Int)
。但我應該得到它ErrorT String IO Int
。
如果我要去的方向錯了這一點,什麼是正確的方法需要IO(或其他單子),並從 單子上下文中調用 手柄錯誤(見foo
函數的例子)
編輯: 顯然它並不清楚我正在嘗試做什麼。也許下面的函數說明什麼,爲什麼我想知道
maybePulseQuit :: Handle -> IO (Either String())
maybePulseQuit h = runErrorT $ do
f <- liftIO $ (communicate h "finished" :: IO (Either String Bool))
(ErrorT . pure) f >>= \b → liftIO $ when b $ liftIO pulseQuit
這工作,但由於結合的還難看。這比之前有案例檢查的版本要清晰得多。這是推薦的方式嗎?
我在想,例如在ErrorT中嘗試(foobar),它會在ErrorT monad中傳播可能的錯誤。 (IO(或e)) – Masse 2010-11-16 13:11:28
我已經添加了一個示例如何傳播錯誤使用'ErrorT',也許它會幫助 – Yuras 2010-11-16 15:02:53