10

私がこの(間違いなく誤解を招く)コードの一部を置いているとしましょう:

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モナド変換子の内部で作業しているので、これはまだ間違っていると感じています。

ここで何が間違っていますか?コードを別の方法で構成する必要がありますか?

4

3 に答える 3

10

parseUserの型を一般化できます

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

そして、手動で持ち上げる必要がなくても(もしあれば)両方で機能しm ~ Either Stringます。m ~ ExceptT String m'Monad m'

やり方は、基本的にinの定義Rightreturnandに置き換えます。LeftthrowErrorparseUser

于 2016-01-04T12:03:16.940 に答える