Help us understand the problem. What is going on with this article?

# 1. ExceptTモナドの定義

エラー処理を行うためのモナドです。

```newtype ExceptT e m a = ExceptT (m (Either e a))

runExceptT :: ExceptT e m a -> m (Either e a)
runExceptT (ExceptT m) = m
```

モナドの定義は以下の通りです。mの計算が失敗した場合(Left)は、計算の後続である k は呼ばれないことがポイントです。

```instance (Monad m) => Monad (ExceptT e m) where
return a = ExceptT \$ return (Right a)

m >>= k = ExceptT \$ do
a <- runExceptT m
case a of
Left e -> return (Left e)
Right x -> runExceptT (k x)

fail = ExceptT . fail
```

# 2. 補助関数 - lift, throwE, catchE

lift は m a を ExceptT e m a に持ち上げるための関数です

```lift :: Monad m => m a -> ExceptT e m a
lift = ExceptT . liftM Right
```

```-- | Promote a function to a monad.
liftM   :: (Monad m) => (a1 -> r) -> m a1 -> m r
liftM f m1              = do { x1 <- m1; return (f x1) }
```
```-- | Signal an exception value @e@.
throwE :: (Monad m) => e -> ExceptT e m a
throwE = ExceptT . return . Left

-- | Handle an exception.
ExceptT e m a               -- ^ the inner computation
-> (e -> ExceptT e' m a)    -- ^ a handler for exceptions in the inner computation
-> ExceptT e' m a
m `catchE` h = ExceptT \$ do
a <- runExceptT m
case a of
Left  l -> runExceptT (h l)
Right r -> return (Right r)
```

# 3. ExceptTの使用例 - StateTの上に乗っけてみる

つまり　ExceptT e m a　モナドの m に StateT を使います。

```import Data.Functor.Identity

--  runState (runExceptT mainTasu) []
--  runState (runExceptT mainTasu) [8]
--  runState (runExceptT mainTasu) [8,7]
--  runState (runExceptT mainTasu) [8,7..0]

type Stack = [Int]

lift :: Monad m => m a -> ExceptT e m a
lift = ExceptT . liftM Right

tasu :: ExceptT String (StateT Stack Identity) Int
tasu = do
-- lift \$ state \$ \xs -> ((), 9:xs)       -- push 9
s <- lift \$ get
case s of
[]  -> throwE "Error: Stack is empty !"
[_] -> throwE "Error: Stack has only one element !"
_  -> do
a <- lift \$ state \$ \(x:xs) -> (x, xs) -- a <- pop
b <- lift \$ state \$ \(x:xs) -> (x, xs) -- b <- pop
return (a+b)

mainTasu :: ExceptT String (StateT Stack Identity) Int
mainTasu = do
a <- tasu   -- pointA
lift \$ state \$ \xs -> ((), a:xs)       -- push a
return a
```

```*Main> runState (runExceptT mainTasu) []
(Left "Error: Stack is empty !",[])
*Main> runState (runExceptT mainTasu) [8]
(Left "Error: Stack has only one element !",[8])
*Main> runState (runExceptT mainTasu) [8,7]
(Right 15,[15])
*Main> runState (runExceptT mainTasu) [8,7..0]
(Right 15,[15,6,5,4,3,2,1,0])
```

Why not register and get more from Qiita?
1. We will deliver articles that match you
By following users and tags, you can catch up information on technical fields that you are interested in as a whole
2. you can read useful information later efficiently
By "stocking" the articles you like, you can search right away
If you already have a Qiita account
Why do not you register as a user and use Qiita more conveniently?
You need to log in to use this function. Qiita can be used more conveniently after logging in.
You seem to be reading articles frequently this month. Qiita can be used more conveniently after logging in.
1. We will deliver articles that match you
By following users and tags, you can catch up information on technical fields that you are interested in as a whole
2. you can read useful information later efficiently
By "stocking" the articles you like, you can search right away