packages feed

either-n-0.1.0.0: src/Data/Either3/Either3T.hs

{-# LANGUAGE DeriveDataTypeable #-}
{-# LANGUAGE DeriveGeneric #-}
{-# LANGUAGE DerivingStrategies #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE LambdaCase #-}
{-# LANGUAGE StandaloneDeriving #-}
{-# LANGUAGE TupleSections #-}
{-# LANGUAGE TypeFamilies #-}
{-# LANGUAGE TypeOperators #-}
-- The lifted MonadState, MonadReader, MonadWriter, MonadError and MonadRWS
-- instances fail the coverage condition for their functional dependencies, as
-- mtl's own lifting instances do, and
-- the Data instance has the context Data (f (Either3 a b c)), as a derived
-- instance for a type applied to a type variable must. Each instance context
-- is on a component of the instance head, so instance resolution terminates.
{-# LANGUAGE UndecidableInstances #-}
{-# OPTIONS_GHC -Wall #-}

{- | 'Either3' inside a type constructor @f@, in the same way that @ExceptT e m a@ is @m (Either e a)@.

Use '_Wrapped' to convert between @Either3T f a b c@ and @f (Either3 a b c)@.
-}
module Data.Either3.Either3T (
  -- * Data type
  Either3T (..),

  -- * Isomorphisms
  either3Identity,
  either3TACB,
  either3TBAC,
  either3TBCA,
  either3TCAB,
  either3TCBA,

  -- * Type aliases
  Either3TIdentity,
  Either3TIO,
  Either3TMaybe,
  Either3TList,

  -- * Optics

  -- ** Classy lenses
  GetEither3T (..),
  HasEither3T (..),

  -- ** Classy prisms
  ReviewEither3T (..),
  AsEither3T (..),
) where

import Control.DeepSeq (NFData (..), NFData1 (..))
import Control.Lens (Each (..), FoldableWithIndex (..), FunctorWithIndex (..), Getter, Iso, Lens', Prism', Review, Rewrapped, TraversableWithIndex (..), Unwrapped, Wrapped (..), iso, lens, mapping, prism', review, unto, view, _Unwrapped, _Wrapped)
import Control.Monad.Cont.Class (MonadCont (..))
import Control.Monad.Error.Class (MonadError (..))
import Control.Monad.IO.Class (MonadIO (..))
import Control.Monad.RWS.Class (MonadRWS)
import Control.Monad.Reader.Class (MonadReader (..))
import Control.Monad.State.Class (MonadState (..))
import Control.Monad.Writer.Class (MonadWriter (..))
import Control.Monad.Zip (MonadZip (..))
import Control.Selective (Selective (..), selectM)
import Data.Bifoldable (Bifoldable (..))
import Data.Bifunctor (Bifunctor (..))
import Data.Bifunctor.Swap (Swap (..))
import Data.Bitraversable (Bitraversable (..))
import Data.Data (Data, Typeable)
import Data.Either3.Either3 (
  AsEither3 (..),
  Either3 (..),
  GetEither3 (..),
  HasEither3 (..),
  ReviewEither3 (..),
  either3ACB,
  either3BAC,
  either3BCA,
  either3CAB,
  either3CBA,
  foldEither3,
 )
import Data.Functor.Alt (Alt (..))
import Data.Functor.Apply (Apply (..))
import Data.Functor.Bind (Bind (..))
import Data.Functor.Classes (Eq1 (..), Eq2 (..), Ord1 (..), Ord2 (..), Show1 (..), Show2 (..), compare1, eq1, showsPrec1, showsUnaryWith)
import Data.Functor.Extend (Extend (..))
import Data.Functor.Identity (Identity (..))
import Data.Lens.Injection.Injection1 (Injection1 (..))
import Data.Lens.Injection.Injection2 (Injection2 (..))
import Data.Lens.Injection.Injection3 (Injection3 (..))
import GHC.Generics (Generic, Generic1)

{- $setup
>>> import Control.DeepSeq(rnf)
>>> import Data.Data(toConstr)
>>> import GHC.Generics(from, to)
>>> import Control.Lens((^?), (#), over, view, review, toListOf, _Wrapped)
>>> import Control.Monad.State(State, runState, modify)
>>> import Control.Monad.Reader(Reader, runReader)
>>> import Control.Monad.Writer(Writer, runWriter)
>>> import Control.Monad.Cont(Cont, runCont)
>>> import Control.Monad.Zip(mzip)
>>> import Control.Selective(select)
>>> import Data.Bifunctor(bimap)
>>> import Data.Bifoldable(bifoldMap)
>>> import Data.Bitraversable(bitraverse)
>>> import Data.Bifunctor.Swap(swap)
>>> import Data.Functor.Alt((<!>))
>>> import Data.Functor.Extend(duplicated)
>>> import Data.Functor.Identity(Identity(..))
>>> import Data.Lens.Injection.Injection1(Injection1(..))
>>> import Data.Lens.Injection.Injection2(Injection2(..))
>>> import Data.Lens.Injection.Injection3(Injection3(..))
>>> let e3 = review reviewEither3 :: Either3 String Bool Int -> Either3TIdentity String Bool Int
-}

{- | An 'Either3' inside @f@.

>>> toConstr (Either3T [Third3 1] :: Either3TList String Bool Int)
Either3T

>>> to (from (Either3T [Third3 1] :: Either3TList String Bool Int)) :: Either3TList String Bool Int
Either3T [Third3 1]
-}
newtype Either3T f a b c
  = Either3T (f (Either3 a b c))
  deriving stock (Generic, Generic1)

deriving stock instance (Typeable f, Data a, Data b, Data c, Data (f (Either3 a b c))) => Data (Either3T f a b c)

-- | 'Either3T' over 'Identity', equivalent to 'Either3'.
type Either3TIdentity = Either3T Identity

-- | 'Either3T' over 'IO'.
type Either3TIO = Either3T IO

-- | 'Either3T' over 'Maybe'.
type Either3TMaybe = Either3T Maybe

-- | 'Either3T' over lists.
type Either3TList = Either3T []

{- | 'Either3' is isomorphic to 'Either3T' over 'Identity'.

>>> view either3Identity (Third3 1 :: Either3 String Bool Int)
Either3T (Identity (Third3 1))

>>> review either3Identity (Either3T (Identity (Second3 True)) :: Either3TIdentity String Bool Int)
Second3 True

It can change the type parameters:

>>> over either3Identity (fmap show) (Third3 1 :: Either3 String Bool Int)
Third3 "1"
-}
either3Identity :: Iso (Either3 a b c) (Either3 a' b' c') (Either3TIdentity a b c) (Either3TIdentity a' b' c')
either3Identity = iso (Either3T . Identity) (runIdentity . view _Wrapped)
{-# INLINE either3Identity #-}

{- | Reorder the type parameters of 'Either3T' to @a c b@, applying 'either3ACB' under @f@.

>>> view either3TACB (Either3T [Second3 True, Third3 1] :: Either3TList String Bool Int)
Either3T [Third3 True,Second3 1]
-}
either3TACB :: (Functor f) => Iso (Either3T f a b c) (Either3T f a' b' c') (Either3T f a c b) (Either3T f a' c' b')
either3TACB =
  _Wrapped . mapping either3ACB . _Unwrapped
{-# INLINE either3TACB #-}

{- | Reorder the type parameters of 'Either3T' to @b a c@, applying 'either3BAC' under @f@.

>>> view either3TBAC (Either3T [First3 "x", Second3 True] :: Either3TList String Bool Int)
Either3T [Second3 "x",First3 True]
-}
either3TBAC :: (Functor f) => Iso (Either3T f a b c) (Either3T f a' b' c') (Either3T f b a c) (Either3T f b' a' c')
either3TBAC =
  _Wrapped . mapping either3BAC . _Unwrapped
{-# INLINE either3TBAC #-}

{- | Reorder the type parameters of 'Either3T' to @b c a@, applying 'either3BCA' under @f@.

>>> view either3TBCA (Either3T [First3 "x", Second3 True] :: Either3TList String Bool Int)
Either3T [Third3 "x",First3 True]
-}
either3TBCA :: (Functor f) => Iso (Either3T f a b c) (Either3T f a' b' c') (Either3T f b c a) (Either3T f b' c' a')
either3TBCA =
  _Wrapped . mapping either3BCA . _Unwrapped
{-# INLINE either3TBCA #-}

{- | Reorder the type parameters of 'Either3T' to @c a b@, applying 'either3CAB' under @f@.

>>> view either3TCAB (Either3T [First3 "x", Third3 1] :: Either3TList String Bool Int)
Either3T [Second3 "x",First3 1]
-}
either3TCAB :: (Functor f) => Iso (Either3T f a b c) (Either3T f a' b' c') (Either3T f c a b) (Either3T f c' a' b')
either3TCAB =
  _Wrapped . mapping either3CAB . _Unwrapped
{-# INLINE either3TCAB #-}

{- | Reorder the type parameters of 'Either3T' to @c b a@, applying 'either3CBA' under @f@.

>>> view either3TCBA (Either3T [First3 "x", Third3 1] :: Either3TList String Bool Int)
Either3T [Third3 "x",First3 1]
-}
either3TCBA :: (Functor f) => Iso (Either3T f a b c) (Either3T f a' b' c') (Either3T f c b a) (Either3T f c' b' a')
either3TCBA =
  _Wrapped . mapping either3CBA . _Unwrapped
{-# INLINE either3TCBA #-}

{- |
>>> view _Wrapped (Either3T [Third3 1, First3 "x"] :: Either3TList String Bool Int)
[Third3 1,First3 "x"]

>>> review _Wrapped [Second3 True] :: Either3TList String Bool Int
Either3T [Second3 True]
-}
instance Wrapped (Either3T f a b c) where
  type Unwrapped (Either3T f a b c) = f (Either3 a b c)
  _Wrapped' =
    iso (\(Either3T x) -> x) Either3T
  {-# INLINE _Wrapped' #-}

{- |
Changes the type constructor from lists to 'Maybe':

>>> over _Wrapped (foldr (const . Just) Nothing) (Either3T [Third3 1, Third3 2] :: Either3TList String Bool Int) :: Either3TMaybe String Bool Int
Either3T (Just (Third3 1))
-}
instance (t ~ Either3T f' a' b' c') => Rewrapped (Either3T f a b c) t

{- |
>>> rnf (Either3T [Third3 1, First3 "x"] :: Either3TList String Bool Int)
()
-}
instance (NFData1 f, NFData a, NFData b, NFData c) => NFData (Either3T f a b c) where
  rnf (Either3T x) =
    liftRnf rnf x
  {-# INLINE rnf #-}

{- |
>>> Either3T [Third3 1] == (Either3T [Third3 1] :: Either3TList String Bool Int)
True

>>> Either3T [Third3 1] == (Either3T [Second3 True] :: Either3TList String Bool Int)
False
-}
instance (Eq1 f, Eq a, Eq b, Eq c) => Eq (Either3T f a b c) where
  Either3T x == Either3T y =
    eq1 x y
  {-# INLINE (==) #-}

instance (Eq1 f, Eq a) => Eq2 (Either3T f a) where
  liftEq2 f g (Either3T x) (Either3T y) =
    liftEq (liftEq2 f g) x y
  {-# INLINE liftEq2 #-}

instance (Eq1 f, Eq a, Eq b) => Eq1 (Either3T f a b) where
  liftEq = liftEq2 (==)
  {-# INLINE liftEq #-}

{- |
>>> compare (Either3T [First3 "x"]) (Either3T [Third3 1] :: Either3TList String Bool Int)
LT
-}
instance (Ord1 f, Ord a, Ord b, Ord c) => Ord (Either3T f a b c) where
  compare (Either3T x) (Either3T y) =
    compare1 x y
  {-# INLINE compare #-}

instance (Ord1 f, Ord a) => Ord2 (Either3T f a) where
  liftCompare2 f g (Either3T x) (Either3T y) =
    liftCompare (liftCompare2 f g) x y
  {-# INLINE liftCompare2 #-}

instance (Ord1 f, Ord a, Ord b) => Ord1 (Either3T f a b) where
  liftCompare = liftCompare2 compare
  {-# INLINE liftCompare #-}

{- |
>>> Either3T [Third3 1, First3 "x"] :: Either3TList String Bool Int
Either3T [Third3 1,First3 "x"]

>>> e3 (Second3 True)
Either3T (Identity (Second3 True))
-}
instance (Show1 f, Show a, Show b, Show c) => Show (Either3T f a b c) where
  showsPrec d (Either3T x) =
    showsUnaryWith showsPrec1 "Either3T" d x
  {-# INLINE showsPrec #-}

instance (Show1 f, Show a) => Show2 (Either3T f a) where
  liftShowsPrec2 sp1 sl1 sp2 sl2 d (Either3T x) =
    showsUnaryWith (liftShowsPrec (liftShowsPrec2 sp1 sl1 sp2 sl2) (liftShowList2 sp1 sl1 sp2 sl2)) "Either3T" d x
  {-# INLINE liftShowsPrec2 #-}

instance (Show1 f, Show a, Show b) => Show1 (Either3T f a b) where
  liftShowsPrec = liftShowsPrec2 showsPrec showList
  {-# INLINE liftShowsPrec #-}

{- | The first value that is 'Third3' wins, otherwise the second value, like 'Either'.

>>> Either3T [First3 "x"] <> Either3T [Third3 1] :: Either3TList String Bool Int
Either3T [Third3 1]
-}
instance (Monad f) => Semigroup (Either3T f a b c) where
  (<>) =
    (<!>)
  {-# INLINE (<>) #-}

{- |
>>> fmap (+ 1) (Either3T [Third3 1, Second3 True] :: Either3TList String Bool Int)
Either3T [Third3 2,Second3 True]
-}
instance (Functor f) => Functor (Either3T f a b) where
  fmap =
    mapEither3T
  {-# INLINE fmap #-}

{- | Runs the effects of the second argument only when the first is 'Third3'.

>>> Either3T [Third3 (+ 1), First3 "x"] <.> Either3T [Third3 1, Third3 2] :: Either3TList String Bool Int
Either3T [Third3 2,Third3 3,First3 "x"]
-}
instance (Monad f) => Apply (Either3T f a b) where
  Either3T x <.> Either3T y =
    Either3T $
      x >>= \case
        First3 a -> pure (First3 a)
        Second3 b -> pure (Second3 b)
        Third3 g -> fmap (fmap g) y
  {-# INLINE (<.>) #-}

{- |
>>> pure 1 :: Either3TList String Bool Int
Either3T [Third3 1]
-}
instance (Monad f) => Applicative (Either3T f a b) where
  pure =
    Either3T . pure . Third3
  {-# INLINE pure #-}
  (<*>) =
    (<.>)
  {-# INLINE (<*>) #-}

instance (Monad f) => Bind (Either3T f a b) where
  (>>-) =
    (>>=)
  {-# INLINE (>>-) #-}

{- |
>>> Either3T [Third3 1, Second3 True] >>= (\x -> Either3T [Third3 x, Third3 (x + 1)]) :: Either3TList String Bool Int
Either3T [Third3 1,Third3 2,Second3 True]
-}
instance (Monad f) => Monad (Either3T f a b) where
  Either3T x >>= k =
    Either3T (x >>= foldEither3 (pure . First3) (pure . Second3) (\c -> let Either3T y = k c in y))
  {-# INLINE (>>=) #-}

{- | The first value that is 'Third3' wins, otherwise the second value, like 'Either'.

>>> Either3T [Second3 True] <!> Either3T [Third3 1] :: Either3TList String Bool Int
Either3T [Third3 1]

>>> Either3T [Second3 True] <!> Either3T [First3 "x"] :: Either3TList String Bool Int
Either3T [First3 "x"]
-}
instance (Monad f) => Alt (Either3T f a b) where
  Either3T x <!> Either3T y =
    Either3T (x >>= foldEither3 (const y) (const y) (pure . Third3))
  {-# INLINE (<!>) #-}

{- |
>>> duplicated (Either3T [Third3 1, First3 "x"] :: Either3TList String Bool Int)
Either3T [Third3 (Either3T [Third3 1]),First3 "x"]
-}
instance (Applicative f) => Extend (Either3T f a b) where
  duplicated =
    fmap (Either3T . pure . Third3)
  {-# INLINE duplicated #-}

{- |
>>> select (pure (Left 1)) (pure (+ 1)) :: Either3TList String Bool Int
Either3T [Third3 2]
-}
instance (Monad f) => Selective (Either3T f a b) where
  select =
    selectM
  {-# INLINE select #-}

{- | Lifts 'liftIO' from @f@.

>>> view _Wrapped (liftIO (pure 1) :: Either3TIO String Bool Int)
Third3 1
-}
instance (MonadIO f) => MonadIO (Either3T f a b) where
  liftIO =
    Either3T . fmap Third3 . liftIO
  {-# INLINE liftIO #-}

{- | Lifts 'fail' from @f@.

>>> fail "x" :: Either3TMaybe String Bool Int
Either3T Nothing
-}
instance (MonadFail f) => MonadFail (Either3T f a b) where
  fail =
    Either3T . fail
  {-# INLINE fail #-}

{- | Lifts 'state' from @f@.

>>> runState (view _Wrapped (modify (+ 1) >> get :: Either3T (State Int) String Bool Int)) 1
(Third3 2,2)
-}
instance (MonadState s f) => MonadState s (Either3T f a b) where
  state =
    Either3T . fmap Third3 . state
  {-# INLINE state #-}

{- | Lifts 'ask' and 'local' from @f@, as the instance for @ExceptT@ does.

>>> runReader (view _Wrapped (local (+ 1) ask :: Either3T (Reader Int) String Bool Int)) 1
Third3 2
-}
instance (MonadReader r f) => MonadReader r (Either3T f a b) where
  ask =
    Either3T (fmap Third3 ask)
  {-# INLINE ask #-}
  local g (Either3T x) =
    Either3T (local g x)
  {-# INLINE local #-}
  reader =
    Either3T . fmap Third3 . reader
  {-# INLINE reader #-}

{- | Lifts 'tell', 'listen' and 'pass' from @f@, as the instance for @MaybeT@ does.

>>> runWriter (view _Wrapped (tell [1] >> listen (tell [2] >> pure 'x') :: Either3T (Writer [Int]) String Bool (Char, [Int])))
(Third3 ('x',[2]),[1,2])

>>> runWriter (view _Wrapped (pass (pure ('x', reverse)) <* tell [1, 2] :: Either3T (Writer [Int]) String Bool Char))
(Third3 'x',[1,2])

>>> runWriter (view _Wrapped (pass (tell [1, 2] >> pure ('x', reverse)) :: Either3T (Writer [Int]) String Bool Char))
(Third3 'x',[2,1])
-}
instance (MonadWriter w f) => MonadWriter w (Either3T f a b) where
  writer =
    Either3T . fmap Third3 . writer
  {-# INLINE writer #-}
  tell =
    Either3T . fmap Third3 . tell
  {-# INLINE tell #-}
  listen (Either3T x) =
    Either3T $ do
      (e, w) <- listen x
      pure (fmap (,w) e)
  {-# INLINE listen #-}
  pass (Either3T x) =
    Either3T $
      pass $ do
        e <- x
        pure $ case e of
          First3 a -> (First3 a, id)
          Second3 b -> (Second3 b, id)
          Third3 (c, g) -> (Third3 c, g)
  {-# INLINE pass #-}

{- | Lifts 'throwError' and 'catchError' from @f@, as the instance for @MaybeT@ does.
'First3' and 'Second3' are values, not errors, so 'catchError' does not catch them.

>>> view _Wrapped (throwError "e" `catchError` (\e -> pure (length e)) :: Either3T (Either String) String Bool Int)
Right (Third3 1)

>>> view _Wrapped (review reviewEither3 (Second3 True) `catchError` (\_ -> pure 1) :: Either3T (Either String) String Bool Int)
Right (Second3 True)
-}
instance (MonadError e f) => MonadError e (Either3T f a b) where
  throwError =
    Either3T . throwError
  {-# INLINE throwError #-}
  catchError (Either3T x) h =
    Either3T (catchError x (\e -> let Either3T y = h e in y))
  {-# INLINE catchError #-}

-- | Lifts 'MonadRWS' from @f@.
instance (MonadRWS r w s f) => MonadRWS r w s (Either3T f a b)

{- | Lifts 'callCC' from @f@, as the instance for @MaybeT@ does.

>>> runCont (view _Wrapped (callCC (\k -> k 1 >> review reviewEither3 (Second3 True)) :: Either3T (Cont r) String Bool Int)) id
Third3 1
-}
instance (MonadCont f) => MonadCont (Either3T f a b) where
  callCC g =
    Either3T $ callCC $ \k ->
      let Either3T y = g (Either3T . k . Third3)
       in y
  {-# INLINE callCC #-}

{- | Lifts 'mzipWith' from @f@, combining each pair of 'Either3' values with
'Control.Applicative.liftA2', as the instance for @MaybeT@ does.

>>> mzip (Either3T [Third3 1, First3 "x"]) (Either3T [Third3 True, Third3 False]) :: Either3TList String Bool (Int, Bool)
Either3T [Third3 (1,True),First3 "x"]
-}
instance (MonadZip f) => MonadZip (Either3T f a b) where
  mzipWith g (Either3T x) (Either3T y) =
    Either3T (mzipWith (liftA2 g) x y)
  {-# INLINE mzipWith #-}

{- | Maps the second and third type parameters.

>>> bimap not (+ 1) (Either3T [Second3 True, Third3 1] :: Either3TList String Bool Int)
Either3T [Second3 False,Third3 2]
-}
instance (Functor f) => Bifunctor (Either3T f a) where
  bimap =
    bimapEither3T
  {-# INLINE bimap #-}

{- | Swaps the second and third type parameters.

>>> swap (Either3T [Second3 True, Third3 1] :: Either3TList String Bool Int)
Either3T [Third3 True,Second3 1]
-}
instance (Functor f) => Swap (Either3T f a) where
  swap (Either3T x) =
    Either3T (fmap swap x)
  {-# INLINE swap #-}

{- |
>>> sum (Either3T [Third3 1, First3 "x", Third3 2] :: Either3TList String Bool Int)
3
-}
instance (Foldable f) => Foldable (Either3T f a b) where
  foldMap =
    foldMapEither3T
  {-# INLINE foldMap #-}

{- |
>>> traverse (\x -> Just (x + 1)) (Either3T [Third3 1, First3 "x"] :: Either3TList String Bool Int)
Just (Either3T [Third3 2,First3 "x"])
-}
instance (Traversable f) => Traversable (Either3T f a b) where
  traverse =
    traverseEither3T
  {-# INLINE traverse #-}

{- |
>>> bifoldMap show show (Either3T [Second3 True, Third3 1] :: Either3TList String Bool Int)
"True1"
-}
instance (Foldable f) => Bifoldable (Either3T f a) where
  bifoldMap =
    bifoldMapEither3T
  {-# INLINE bifoldMap #-}

{- |
>>> bitraverse (Just . not) (Just . (+ 1)) (Either3T [Second3 True, Third3 1] :: Either3TList String Bool Int)
Just (Either3T [Second3 False,Third3 2])
-}
instance (Traversable f) => Bitraversable (Either3T f a) where
  bitraverse =
    bitraverseEither3T
  {-# INLINE bitraverse #-}

{- Fusion

The 'Functor', 'Foldable', 'Traversable', 'Bifunctor', 'Bifoldable' and
'Bitraversable' methods delegate to the functions below, which are not
inlined before phase 1, so that the rewrite rules, which are active before
phase 1, can fuse compositions of them. Each rule is an instance of the functor law
@fmap f . fmap g = fmap (f . g)@, or of the corresponding law for 'bimap',
'foldMap', 'traverse', 'bifoldMap' or 'bitraverse', for both 'Either3' and
@f@, so the rules assume that the instances for @f@ are lawful.
-}

mapEither3T :: (Functor f) => (c -> d) -> Either3T f a b c -> Either3T f a b d
mapEither3T g (Either3T x) =
  Either3T (fmap (fmap g) x)
{-# NOINLINE [1] mapEither3T #-}

bimapEither3T :: (Functor f) => (b -> b') -> (c -> c') -> Either3T f a b c -> Either3T f a b' c'
bimapEither3T g h (Either3T x) =
  Either3T (fmap (bimap g h) x)
{-# NOINLINE [1] bimapEither3T #-}

foldMapEither3T :: (Foldable f, Monoid m) => (c -> m) -> Either3T f a b c -> m
foldMapEither3T g (Either3T x) =
  foldMap (foldMap g) x
{-# NOINLINE [1] foldMapEither3T #-}

traverseEither3T :: (Traversable f, Applicative g) => (c -> g d) -> Either3T f a b c -> g (Either3T f a b d)
traverseEither3T g (Either3T x) =
  Either3T <$> traverse (traverse g) x
{-# NOINLINE [1] traverseEither3T #-}

bifoldMapEither3T :: (Foldable f, Monoid m) => (b -> m) -> (c -> m) -> Either3T f a b c -> m
bifoldMapEither3T g h (Either3T x) =
  foldMap (bifoldMap g h) x
{-# NOINLINE [1] bifoldMapEither3T #-}

bitraverseEither3T :: (Traversable f, Applicative g) => (b -> g b') -> (c -> g c') -> Either3T f a b c -> g (Either3T f a b' c')
bitraverseEither3T g h (Either3T x) =
  Either3T <$> traverse (bitraverse g h) x
{-# NOINLINE [1] bitraverseEither3T #-}

{-# RULES
"Either3T fmap/fmap" [~1] forall f g x.
  mapEither3T f (mapEither3T g x) =
    mapEither3T (f . g) x
"Either3T bimap/bimap" [~1] forall f g h k x.
  bimapEither3T f g (bimapEither3T h k x) =
    bimapEither3T (f . h) (g . k) x
"Either3T fmap/bimap" [~1] forall f g h x.
  mapEither3T f (bimapEither3T g h x) =
    bimapEither3T g (f . h) x
"Either3T bimap/fmap" [~1] forall f g h x.
  bimapEither3T f g (mapEither3T h x) =
    bimapEither3T f (g . h) x
"Either3T foldMap/fmap" [~1] forall f g x.
  foldMapEither3T f (mapEither3T g x) =
    foldMapEither3T (f . g) x
"Either3T traverse/fmap" [~1] forall f g x.
  traverseEither3T f (mapEither3T g x) =
    traverseEither3T (f . g) x
"Either3T bifoldMap/bimap" [~1] forall f g h k x.
  bifoldMapEither3T f g (bimapEither3T h k x) =
    bifoldMapEither3T (f . h) (g . k) x
"Either3T bitraverse/bimap" [~1] forall f g h k x.
  bitraverseEither3T f g (bimapEither3T h k x) =
    bitraverseEither3T (f . h) (g . k) x
  #-}

-- | The index is always @()@, as for 'Maybe'.
instance (Functor f) => FunctorWithIndex () (Either3T f a b) where
  imap g =
    fmap (g ())
  {-# INLINE imap #-}

instance (Foldable f) => FoldableWithIndex () (Either3T f a b) where
  ifoldMap g =
    foldMap (g ())
  {-# INLINE ifoldMap #-}

instance (Traversable f) => TraversableWithIndex () (Either3T f a b) where
  itraverse g =
    traverse (g ())
  {-# INLINE itraverse #-}

{- | Traverses every value inside @f@.

>>> toListOf each (Either3T [First3 1, Second3 2, Third3 3] :: Either3TList Int Int Int)
[1,2,3]
-}
instance (Traversable f) => Each (Either3T f a a a) (Either3T f b b b) a b where
  each g (Either3T x) =
    Either3T <$> traverse (each g) x
  {-# INLINE each #-}

{- |
>>> e3 (First3 "x") ^? _I1
Just "x"
-}
instance Injection1 (Either3T Identity a b c) (Either3T Identity a' b c) a a' where
  _I1 =
    _Wrapped . _Wrapped . _I1
  {-# INLINE _I1 #-}

{- |
>>> e3 (Second3 True) ^? _I2
Just True
-}
instance Injection2 (Either3T Identity a b c) (Either3T Identity a b' c) b b' where
  _I2 =
    _Wrapped . _Wrapped . _I2
  {-# INLINE _I2 #-}

{- |
>>> e3 (Third3 1) ^? _I3
Just 1

>>> e3 (First3 "x") ^? _I3
Nothing
-}
instance Injection3 (Either3T Identity a b c) (Either3T Identity a b c') c c' where
  _I3 =
    _Wrapped . _Wrapped . _I3
  {-# INLINE _I3 #-}

{- |
>>> view getEither3 (e3 (Third3 1))
Third3 1
-}
instance GetEither3 (Either3T Identity a b c) a b c where
  getEither3 =
    _Wrapped . _Wrapped
  {-# INLINE getEither3 #-}

{- |
>>> setEither3 (Second3 True) (e3 (Third3 1))
Either3T (Identity (Second3 True))
-}
instance HasEither3 (Either3T Identity a b c) a b c where
  setEither3 e _ =
    Either3T (Identity e)
  {-# INLINE setEither3 #-}

{- | Any 'Either3' can be put in an 'Applicative' @f@.

>>> review reviewEither3 (Second3 True) :: Either3TMaybe String Bool Int
Either3T (Just (Second3 True))
-}
instance (Applicative f) => ReviewEither3 (Either3T f a b c) a b c where
  reviewEither3 =
    unto (Either3T . pure)
  {-# INLINE reviewEither3 #-}

{- |
>>> matchEither3 (e3 (Third3 1))
Just (Third3 1)

>>> e3 (Third3 1) ^? _Either3
Just (Third3 1)
-}
instance AsEither3 (Either3T Identity a b c) a b c where
  matchEither3 (Either3T (Identity e)) =
    Just e
  {-# INLINE matchEither3 #-}

-- | Class for types that can be viewed as an 'Either3T'.
class GetEither3T s f a b c | s -> f a b c where
  getEither3T :: Getter s (Either3T f a b c)

instance GetEither3T (Either3T f a b c) f a b c where
  getEither3T = id
  {-# INLINE getEither3T #-}

{- | Class for types that have a 'Lens'' to an 'Either3T'. Instances define
'setEither3T'; the lens 'either3T' follows from it and from 'getEither3T'.

>>> setEither3T (Either3T [Third3 2]) (Either3T [Third3 1] :: Either3TList String Bool Int)
Either3T [Third3 2]
-}
class (GetEither3T s f a b c) => HasEither3T s f a b c | s -> f a b c where
  {-# MINIMAL setEither3T #-}

  setEither3T :: Either3T f a b c -> s -> s

  either3T :: Lens' s (Either3T f a b c)
  either3T = lens (view getEither3T) (flip setEither3T)
  {-# INLINE either3T #-}

instance HasEither3T (Either3T f a b c) f a b c where
  setEither3T = const
  {-# INLINE setEither3T #-}

-- | Class for types that can be constructed from an 'Either3T'.
class ReviewEither3T t f a b c | t -> f a b c where
  reviewEither3T :: Review t (Either3T f a b c)

instance ReviewEither3T (Either3T f a b c) f a b c where
  reviewEither3T = unto id
  {-# INLINE reviewEither3T #-}

{- | Class for types that have a 'Prism'' to an 'Either3T'. Instances define
'matchEither3T'; the prism '_Either3T' follows from it and from 'reviewEither3T'.

>>> matchEither3T (Either3T [Third3 1] :: Either3TList String Bool Int)
Just (Either3T [Third3 1])
-}
class (ReviewEither3T t f a b c) => AsEither3T t f a b c | t -> f a b c where
  {-# MINIMAL matchEither3T #-}

  matchEither3T :: t -> Maybe (Either3T f a b c)

  _Either3T :: Prism' t (Either3T f a b c)
  _Either3T = prism' (review reviewEither3T) matchEither3T
  {-# INLINE _Either3T #-}

instance AsEither3T (Either3T f a b c) f a b c where
  matchEither3T = Just
  {-# INLINE matchEither3T #-}