summaryrefslogtreecommitdiff
path: root/Haskell-book/26/MaybeT/src/Either.hs
blob: e09bfe6a38fbbfab68da7c0a22809030aec639ff (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
module Either where

import Control.Monad (liftM)
import MonadTrans
import MonadIO

newtype EitherT e m a =
    EitherT { runEitherT :: m (Either e a) }

-- 1
instance Functor m => Functor (EitherT e m) where
    fmap f (EitherT x) = EitherT $ (fmap . fmap) f x

-- 2
instance Applicative m => Applicative (EitherT e m) where
    pure x = EitherT $ pure $ pure x

    (EitherT f) <*> (EitherT a) = EitherT $ (<*>) <$> f <*> a

-- 3
instance Monad m => Monad (EitherT e m) where
    return = pure

    (EitherT em) >>= f = EitherT $ do
        v <- em
        case v of
            Left y -> return $ Left y
            Right y -> runEitherT (f y)


-- 4
-- transformer version of swapEither.
-- Hint: write swapEither first, then swapEitherT in terms of the former.
swapEither :: Either e a -> Either a e
swapEither (Left x) = Right x
swapEither (Right y) = Left y

swapEitherT :: (Functor m)
            => EitherT e m a
            -> EitherT a m e
swapEitherT (EitherT x) = EitherT $ fmap swapEither x

-- 5. Write the transformer variant of the either catamorphism.
eitherT :: Monad m
        => (a -> m c)
        -> (b -> m c)
        -> EitherT a m b
        -> m c
eitherT f g (EitherT x) = x >>= (either f g)

instance MonadTrans (EitherT e) where
    lift = EitherT . liftM Right

instance (MonadIO m)
  => MonadIO (EitherT e m) where
      liftIO = lift . liftIO