rom*_*ovs 7 monads haskell monad-transformers either lifting
假设我有这个(可以说是误导的)代码片段:
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
Run Code Online (Sandbox Code Playgroud)
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
Run Code Online (Sandbox Code Playgroud)
什么是提升的最标准的方式Either为ExceptT?我觉得必须有一些方法,因为Either String是一个实例MonadError.
我写了自己的提升功能:
liftEither :: (Monad m, MonadError a (Either a)) => Either a b -> ExceptT a m b
liftEither = either throwError return
Run Code Online (Sandbox Code Playgroud)
但对我来说,这仍然是错误的,因为我已经在ExceptTmonad变换器内部工作了
.
我在这做错了什么?我应该以不同方式构建代码吗?
你可以将parseUser类型概括为
parseUser :: (MonadError String m) => String -> m User
Run Code Online (Sandbox Code Playgroud)
然后它可以在at m ~ Either String和at m ~ ExceptT String m'(如果只是Monad m')工作,无需任何手动提升.
做到这一点的方法是基本取代Right与return和Left与throwError在parseUser的定义.