    -- |
    -- Module: Optics.IxAffineFold
    -- Description: An indexed version of an 'Optics.AffineFold.AffineFold'.
    --
    -- An 'IxAffineFold' is an indexed version of an 'Optics.AffineFold.AffineFold'.
    -- See the "Indexed optics" section of the overview documentation in the
    -- @Optics@ module of the main @optics@ package for more details on indexed
    -- optics.
    --
    module Optics.IxAffineFold
      (
      -- * Formation
        IxAffineFold

      -- * Introduction
      , iafolding

      -- * Elimination
      , ipreview
      , ipreviews

      -- * Computation
      -- |
      --
      -- @
      -- 'ipreview' ('iafolding' f) ≡ f
      -- @

      -- * Additional introduction forms
      , iafoldVL

      -- * Additional elimination forms
      , iatraverseOf_

      -- * Combinators
      , filteredBy

      -- * Monoid structure
      -- | 'IxAffineFold' admits a monoid structure where 'iafailing' combines folds
      -- (returning a result from the second fold only if the first returns none)
      -- and the identity element is 'Optics.IxAffineTraversal.ignored' (which
      -- returns no results).
      --
      -- /Note:/ There is no 'Optics.IxFold.isumming' equivalent that returns an
      -- 'IxAffineFold', because it would not need to return more than one result.
      --
      -- There is no 'Semigroup' or 'Monoid' instance for 'IxAffineFold', because
      -- there is not a unique choice of monoid to use that works for all optics,
      -- and the ('<>') operator could not be used to combine optics of different
      -- kinds.
      , iafailing

      -- * Subtyping
      , An_AffineFold
      ) where

    import Data.Profunctor.Indexed

    import Optics.AffineFold
    import Optics.Internal.Bi
    import Optics.Internal.Indexed
    import Optics.Internal.Optic
    import Optics.Internal.Utils

    -- | Type synonym for an indexed affine fold.
    type IxAffineFold i s a = Optic' An_AffineFold (WithIx i) s a

    -- | Obtain an 'IxAffineFold' by lifting 'itraverse_' like function.
    --
    -- @
    -- 'aifoldVL' '.' 'iatraverseOf_' ≡ 'id'
    -- 'aitraverseOf_' '.' 'iafoldVL' ≡ 'id'
    -- @
    --
    -- @since 0.3
    iafoldVL
      :: (forall f. Functor f => (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v)
      -> IxAffineFold i s a
    iafoldVL :: forall i a u s v.
    (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v)
    -> IxAffineFold i s a
    iafoldVL forall (f :: * -> *).
    Functor f =>
    (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v
    f = (forall (p :: * -> * -> * -> *) i.
     Profunctor p =>
     Optic_ An_AffineFold p i (Curry (WithIx i) i) s s a a)
    -> Optic An_AffineFold (WithIx i) s s a a
    forall k (is :: IxList) s t a b.
    (forall (p :: * -> * -> * -> *) i.
     Profunctor p =>
     Optic_ k p i (Curry is i) s t a b)
    -> Optic k is s t a b
    Optic (p (i -> i) s v -> p (i -> i) s s
    forall (p :: * -> * -> * -> *) i c a b.
    (Profunctor p, Bicontravariant p) =>
    p i c a -> p i c b
    rphantom (p (i -> i) s v -> p (i -> i) s s)
    -> (p i a a -> p (i -> i) s v) -> p i a a -> p (i -> i) s s
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v)
    -> p i a u -> p (i -> i) s v
    forall i a b s t j.
    (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f b) -> s -> f t)
    -> p j a b -> p (i -> j) s t
    forall (p :: * -> * -> * -> *) i a b s t j.
    Visiting p =>
    (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f b) -> s -> f t)
    -> p j a b -> p (i -> j) s t
    ivisit (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v
    forall (f :: * -> *).
    Functor f =>
    (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v
    f (p i a u -> p (i -> i) s v)
    -> (p i a a -> p i a u) -> p i a a -> p (i -> i) s v
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . p i a a -> p i a u
    forall (p :: * -> * -> * -> *) i c a b.
    (Profunctor p, Bicontravariant p) =>
    p i c a -> p i c b
    rphantom)
    {-# INLINE iafoldVL #-}

    -- | Retrieve the value along with its index targeted by an 'IxAffineFold'.
    ipreview
      :: (Is k An_AffineFold, is `HasSingleIndex` i)
      => Optic' k is s a
      -> s -> Maybe (i, a)
    ipreview :: forall k (is :: IxList) i s a.
    (Is k An_AffineFold, HasSingleIndex is i) =>
    Optic' k is s a -> s -> Maybe (i, a)
    ipreview Optic' k is s a
    o = Optic' k is s a -> (i -> a -> (i, a)) -> s -> Maybe (i, a)
    forall k (is :: IxList) i s a r.
    (Is k An_AffineFold, HasSingleIndex is i) =>
    Optic' k is s a -> (i -> a -> r) -> s -> Maybe r
    ipreviews Optic' k is s a
    o (,)
    {-# INLINE ipreview #-}

    -- | Retrieve a function of the value and its index targeted by an
    -- 'IxAffineFold'.
    ipreviews
      :: (Is k An_AffineFold, is `HasSingleIndex` i)
      => Optic' k is s a
      -> (i -> a -> r) -> s -> Maybe r
    ipreviews :: forall k (is :: IxList) i s a r.
    (Is k An_AffineFold, HasSingleIndex is i) =>
    Optic' k is s a -> (i -> a -> r) -> s -> Maybe r
    ipreviews Optic' k is s a
    o = \i -> a -> r
    f -> IxForgetM r (i -> i) s s -> (i -> i) -> s -> Maybe r
    forall r i a b. IxForgetM r i a b -> i -> a -> Maybe r
    runIxForgetM
      (Optic An_AffineFold is s s a a
    -> Optic_ An_AffineFold (IxForgetM r) i (Curry is i) s s a a
    forall (p :: * -> * -> * -> *) k (is :: IxList) s t a b i.
    Profunctor p =>
    Optic k is s t a b -> Optic_ k p i (Curry is i) s t a b
    getOptic (forall destKind srcKind (is :: IxList) s t a b.
    Is srcKind destKind =>
    Optic srcKind is s t a b -> Optic destKind is s t a b
    castOptic @An_AffineFold Optic' k is s a
    o) (IxForgetM r i a a -> IxForgetM r (i -> i) s s)
    -> ((i -> a -> Maybe r) -> IxForgetM r i a a)
    -> (i -> a -> Maybe r)
    -> IxForgetM r (i -> i) s s
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (i -> a -> Maybe r) -> IxForgetM r i a a
    forall r i a b. (i -> a -> Maybe r) -> IxForgetM r i a b
    IxForgetM ((i -> a -> Maybe r) -> IxForgetM r (i -> i) s s)
    -> (i -> a -> Maybe r) -> IxForgetM r (i -> i) s s
    forall a b. (a -> b) -> a -> b
    $ \i
    i -> r -> Maybe r
    forall a. a -> Maybe a
    Just (r -> Maybe r) -> (a -> r) -> a -> Maybe r
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . i -> a -> r
    f i
    i)
      i -> i
    forall a. a -> a
    id
    {-# INLINE ipreviews #-}

    -- | Traverse over the target of an 'IxAffineFold', computing a 'Functor'-based
    -- answer, but unlike 'Optics.IxAffineTraversal.iatraverseOf' do not construct a
    -- new structure.
    --
    -- @since 0.3
    iatraverseOf_
      :: (Is k An_AffineFold, Functor f, is `HasSingleIndex` i)
      => Optic' k is s a
      -> (forall r. r -> f r) -> (i -> a -> f u) -> s -> f ()
    iatraverseOf_ :: forall k (f :: * -> *) (is :: IxList) i s a u.
    (Is k An_AffineFold, Functor f, HasSingleIndex is i) =>
    Optic' k is s a
    -> (forall r. r -> f r) -> (i -> a -> f u) -> s -> f ()
    iatraverseOf_ Optic' k is s a
    o forall r. r -> f r
    point i -> a -> f u
    f s
    s = case Optic' k is s a -> s -> Maybe (i, a)
    forall k (is :: IxList) i s a.
    (Is k An_AffineFold, HasSingleIndex is i) =>
    Optic' k is s a -> s -> Maybe (i, a)
    ipreview Optic' k is s a
    o s
    s of
      Just (i
    i, a
    a) -> () () -> f u -> f ()
    forall a b. a -> f b -> f a
    forall (f :: * -> *) a b. Functor f => a -> f b -> f a
    <$ i -> a -> f u
    f i
    i a
    a
      Maybe (i, a)
    Nothing     -> () -> f ()
    forall r. r -> f r
    point ()
    {-# INLINE iatraverseOf_ #-}

    -- | Create an 'IxAffineFold' from a partial function.
    iafolding :: (s -> Maybe (i, a)) -> IxAffineFold i s a
    iafolding :: forall s i a. (s -> Maybe (i, a)) -> IxAffineFold i s a
    iafolding s -> Maybe (i, a)
    g = (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f s) -> s -> f s)
    -> IxAffineFold i s a
    forall i a u s v.
    (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v)
    -> IxAffineFold i s a
    iafoldVL (\forall r. r -> f r
    point i -> a -> f s
    f s
    s -> f s -> ((i, a) -> f s) -> Maybe (i, a) -> f s
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (s -> f s
    forall r. r -> f r
    point s
    s) ((i -> a -> f s) -> (i, a) -> f s
    forall a b c. (a -> b -> c) -> (a, b) -> c
    uncurry' i -> a -> f s
    f) (Maybe (i, a) -> f s) -> Maybe (i, a) -> f s
    forall a b. (a -> b) -> a -> b
    $ s -> Maybe (i, a)
    g s
    s)
    {-# INLINE iafolding #-}

    -- | Obtain a potentially empty 'IxAffineFold' by taking the element from
    -- another 'AffineFold' and using it as an index.
    --
    -- @since 0.3
    filteredBy :: Is k An_AffineFold  => Optic' k is a i -> IxAffineFold i a a
    filteredBy :: forall k (is :: IxList) a i.
    Is k An_AffineFold =>
    Optic' k is a i -> IxAffineFold i a a
    filteredBy Optic' k is a i
    p = (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f a) -> a -> f a)
    -> IxAffineFold i a a
    forall i a u s v.
    (forall (f :: * -> *).
     Functor f =>
     (forall r. r -> f r) -> (i -> a -> f u) -> s -> f v)
    -> IxAffineFold i s a
    iafoldVL ((forall (f :: * -> *).
      Functor f =>
      (forall r. r -> f r) -> (i -> a -> f a) -> a -> f a)
     -> IxAffineFold i a a)
    -> (forall (f :: * -> *).
        Functor f =>
        (forall r. r -> f r) -> (i -> a -> f a) -> a -> f a)
    -> IxAffineFold i a a
    forall a b. (a -> b) -> a -> b
    $ \forall r. r -> f r
    point i -> a -> f a
    f a
    s -> case Optic' k is a i -> a -> Maybe i
    forall k (is :: IxList) s a.
    Is k An_AffineFold =>
    Optic' k is s a -> s -> Maybe a
    preview Optic' k is a i
    p a
    s of
      Just i
    i  -> i -> a -> f a
    f i
    i a
    s
      Maybe i
    Nothing -> a -> f a
    forall r. r -> f r
    point a
    s
    {-# INLINE filteredBy #-}

    -- | Try the first 'IxAffineFold'. If it returns no entry, try the second one.
    --
    iafailing
      :: (Is k An_AffineFold, Is l An_AffineFold,
          is1 `HasSingleIndex` i, is2 `HasSingleIndex` i)
      => Optic' k is1 s a
      -> Optic' l is2 s a
      -> IxAffineFold i s a
    iafailing :: forall k l (is1 :: IxList) i (is2 :: IxList) s a.
    (Is k An_AffineFold, Is l An_AffineFold, HasSingleIndex is1 i,
     HasSingleIndex is2 i) =>
    Optic' k is1 s a -> Optic' l is2 s a -> IxAffineFold i s a
    iafailing Optic' k is1 s a
    a Optic' l is2 s a
    b = Optic An_AffineFold '[] s s a a
    -> Optic An_AffineFold (WithIx i) s s a a
    -> Optic An_AffineFold (WithIx i) s s a a
    forall (is :: IxList) i k s t a b.
    HasSingleIndex is i =>
    Optic k '[] s t a b -> Optic k is s t a b -> Optic k is s t a b
    conjoined (Optic' k is1 s a
    -> Optic' l is2 s a -> Optic An_AffineFold '[] s s a a
    forall k l (is :: IxList) s a (js :: IxList).
    (Is k An_AffineFold, Is l An_AffineFold) =>
    Optic' k is s a -> Optic' l js s a -> AffineFold s a
    afailing Optic' k is1 s a
    a Optic' l is2 s a
    b) (Optic An_AffineFold (WithIx i) s s a a
     -> Optic An_AffineFold (WithIx i) s s a a)
    -> Optic An_AffineFold (WithIx i) s s a a
    -> Optic An_AffineFold (WithIx i) s s a a
    forall a b. (a -> b) -> a -> b
    $ (s -> Maybe (i, a)) -> Optic An_AffineFold (WithIx i) s s a a
    forall s i a. (s -> Maybe (i, a)) -> IxAffineFold i s a
    iafolding ((s -> Maybe (i, a)) -> Optic An_AffineFold (WithIx i) s s a a)
    -> (s -> Maybe (i, a)) -> Optic An_AffineFold (WithIx i) s s a a
    forall a b. (a -> b) -> a -> b
    $ \s
    s ->
      Maybe (i, a)
    -> ((i, a) -> Maybe (i, a)) -> Maybe (i, a) -> Maybe (i, a)
    forall b a. b -> (a -> b) -> Maybe a -> b
    maybe (Optic' l is2 s a -> s -> Maybe (i, a)
    forall k (is :: IxList) i s a.
    (Is k An_AffineFold, HasSingleIndex is i) =>
    Optic' k is s a -> s -> Maybe (i, a)
    ipreview Optic' l is2 s a
    b s
    s) (i, a) -> Maybe (i, a)
    forall a. a -> Maybe a
    Just (Optic' k is1 s a -> s -> Maybe (i, a)
    forall k (is :: IxList) i s a.
    (Is k An_AffineFold, HasSingleIndex is i) =>
    Optic' k is s a -> s -> Maybe (i, a)
    ipreview Optic' k is1 s a
    a s
    s)
    infixl 3 `iafailing` -- Same as (<|>)
    {-# INLINE iafailing #-}