我无法抓住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