假设我有一段代码(可能是误导性的):
import System.Environment (getArgs)
import Control.Monad.Except
parseArgs :: ExceptT String IO User
parseArgs =
do
args <- lift getArgs
case safeHead args of
Just admin -> parseUser admin
Nothing -> throwError "No admin specified"
parseUser :: String -> Either String User
-- implementation elided
safeHead :: [a] -> Maybe a
-- implementation elided
main =
do
r <- runExceptT parseArgs
case r of
Left err -> putStrLn $ "ERROR: " ++ err
Right res -> print res
ghc
给了我以下错误:
Couldn't match expected type ‘ExceptT String IO User’
with actual type ‘Either String User’
In the expression: parseUser admin
In a case alternative: Just admin -> parseUser admin
将Either
提升为ExceptT
的最标准方法是什么?我觉得一定有办法,因为Either String
是MonadError
的一个实例。
我写了自己的提升函数:
liftEither :: (Monad m, MonadError a (Either a)) => Either a b -> ExceptT a m b
liftEither = either throwError return
但对我来说,这仍然是错误的,因为我已经在ExceptT
monad转换器中工作了。
我在这里做错了什么?我应该以不同的方式构造我的代码吗?
发布于 2016-01-04 20:03:17
您可以将parseUser
的类型概括为
parseUser :: (MonadError String m) => String -> m User
然后,它可以在m ~ Either String
和m ~ ExceptT String m'
(如果只有Monad m'
)上工作,而不需要任何手动提升。
要做到这一点,在parseUser
的定义中,基本上是用return
替换Right
,用throwError
替换Left
。
发布于 2018-06-07 05:36:10
如果您使用的是transformers
而不是mtl
,那么您可以使用Control.Error.Safe
中的tryRight
。
tryRight :: Monad m => Either e a -> ExceptT e m a
发布于 2021-08-03 15:23:10
您可以在transformers
(Control.Monad.Trans.Except)中使用except
:
except :: Monad m => Either e a -> ExceptT e m a
它被定义为ibotty在评论中建议的。
因为它不是MonadError
,所以它和你的liftEither
有点不同。您可以在ExceptT适用的任何地方使用它。
顺便说一句,已经有了一个liftEither
,这是不同的:
liftEither :: MonadError e m => Either e a -> m a
。
我不认为这个对你有什么用处。
https://stackoverflow.com/questions/34588488
复制相似问题