Допустим, у меня есть этот (возможно, вводящий в заблуждение) фрагмент кода:
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
.
Что я здесь делаю неправильно? Должен ли я структурировать свой код по-другому?
ExceptT . return
?ExceptT = ExceptT (m (Either e a))
, поэтомуreturn
приводит вас кIO (Either String User)
, аExceptT
(как конструктор/функция) кExceptT String IO User
. - person ibotty   schedule 04.01.2016liftEither
звучит как правильный ответ для меня (или ответ Кактуса об обобщении типаparseUser
. - person Jonathan Cast   schedule 07.06.2018