假设我有这段(可以说是误导)代码:
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)变压器。我在这里做错了什么?我应该以不同的方式构建我的代码吗?
最佳答案
你可以概括parseUser
的类型为
parseUser :: (MonadError String m) => String -> m User
然后它可以在
m ~ Either String
上工作在 m ~ ExceptT String m'
(如果只有 Monad m'
)无需任何手动提升。这样做的方法是基本替换
Right
与 return
和 Left
与 throwError
在 parseUser
的定义。
关于haskell - 自动将 Either 提升到 exceptT,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34588488/