2016-01-04 2 views
6

Disons que j'ai cette (sans doute induits en erreur) morceau de code autour de la pose:ascenseur soit à ExceptT automatiquement

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 me donne l'erreur suivante:

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 

Quelle est la façon la plus standard soulever un Either dans un ExceptT? Je pense qu'il doit y avoir un certain chemin depuis Either String est une instance de MonadError.

j'ai écrit ma propre fonction de levage:

liftEither :: (Monad m, MonadError a (Either a)) => Either a b -> ExceptT a m b 
liftEither = either throwError return 

Mais pour moi, cela se sent encore mal puisque je travaille déjà à l'intérieur du transformateur ExceptT monade.

Qu'est-ce que je fais mal ici? Dois-je structurer mon code différemment?

+1

Qu'en est-il de 'ExceptT. retour'? 'ExceptT = ExceptT (m (Either e a))', donc 'return' vous conduit à' IO (Soit String User) 'et' ExceptT' (comme constructeur/fonction) à 'ExceptT String IO User'. – ibotty

Répondre

7

Vous pouvez généraliser le type de parseUser à

parseUser :: (MonadError String m) => String -> m User 

et il serait alors travailler à la fois à m ~ Either String et à m ~ ExceptT String m' (si seulement Monad m') sans levage manuel nécessaire.

La façon de le faire est de remplacer essentiellement Right avec return et Left avec throwError dans la définition de parseUser.

+2

Notez que pour la contrainte 'MonadError String m' ghc a besoin de l'extension' FlexibleContexts' (voir http://stackoverflow.com/a/22795830/905686). – user905686