    -- |
    -- Module: Optics.IxGetter
    -- Description: An indexed version of a 'Optics.Getter.Getter'.
    --
    -- An 'IxGetter' is an indexed version of a 'Optics.Getter.Getter'. 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.IxGetter
      (
      -- * Formation
        IxGetter

      -- * Introduction
      , ito
      , selfIndex

      -- * Elimination
      , iview
      , iviews

      -- * Subtyping
      , A_Getter
      ) where

    import Data.Profunctor.Indexed

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

    -- | Type synonym for an indexed getter.
    type IxGetter i s a = Optic' A_Getter (WithIx i) s a

    -- | Build an indexed getter from a function.
    --
    -- >>> iview (ito id) ('i', 'x')
    -- ('i','x')
    ito :: (s -> (i, a)) -> IxGetter i s a
    ito :: forall s i a. (s -> (i, a)) -> IxGetter i s a
    ito s -> (i, a)
    f = (forall (p :: * -> * -> * -> *) i.
     Profunctor p =>
     Optic_ A_Getter p i (Curry (WithIx i) i) s s a a)
    -> Optic A_Getter (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 ((s -> (i, a)) -> p (i -> i) (i, a) s -> p (i -> i) s s
    forall a b i c. (a -> b) -> p i b c -> p i a c
    forall (p :: * -> * -> * -> *) a b i c.
    Profunctor p =>
    (a -> b) -> p i b c -> p i a c
    lmap s -> (i, a)
    f (p (i -> i) (i, a) s -> p (i -> i) s s)
    -> (p i a a -> p (i -> i) (i, a) s) -> p i a a -> p (i -> i) s s
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (forall (f :: * -> *).
     Functor f =>
     (i -> a -> f s) -> (i, a) -> f s)
    -> p i a s -> p (i -> i) (i, a) s
    forall i a b s t j.
    (forall (f :: * -> *). Functor f => (i -> a -> f b) -> s -> f t)
    -> p j a b -> p (i -> j) s t
    forall (p :: * -> * -> * -> *) i a b s t j.
    Strong p =>
    (forall (f :: * -> *). Functor f => (i -> a -> f b) -> s -> f t)
    -> p j a b -> p (i -> j) s t
    ilinear (i -> a -> f s) -> (i, a) -> f s
    forall a b c. (a -> b -> c) -> (a, b) -> c
    forall (f :: * -> *). Functor f => (i -> a -> f s) -> (i, a) -> f s
    uncurry' (p i a s -> p (i -> i) (i, a) s)
    -> (p i a a -> p i a s) -> p i a a -> p (i -> i) (i, a) s
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . p i a a -> p i a s
    forall (p :: * -> * -> * -> *) i c a b.
    (Profunctor p, Bicontravariant p) =>
    p i c a -> p i c b
    rphantom)
    {-# INLINE ito #-}

    -- | Use a value itself as its own index. This is essentially an indexed version
    -- of 'Optics.Iso.equality'.
    selfIndex :: IxGetter a a a
    selfIndex :: forall a. IxGetter a a a
    selfIndex = (a -> (a, a)) -> IxGetter a a a
    forall s i a. (s -> (i, a)) -> IxGetter i s a
    ito (\a
    a -> (a
    a, a
    a))
    {-# INLINE selfIndex #-}

    -- | View the value pointed to by an indexed getter.
    iview
      :: (Is k A_Getter, is `HasSingleIndex` i)
      => Optic' k is s a -> s -> (i, a)
    iview :: forall k (is :: IxList) i s a.
    (Is k A_Getter, HasSingleIndex is i) =>
    Optic' k is s a -> s -> (i, a)
    iview Optic' k is s a
    o = Optic' k is s a -> (i -> a -> (i, a)) -> s -> (i, a)
    forall k (is :: IxList) i s a r.
    (Is k A_Getter, HasSingleIndex is i) =>
    Optic' k is s a -> (i -> a -> r) -> s -> r
    iviews Optic' k is s a
    o (,)
    {-# INLINE iview #-}

    -- | View the function of the value pointed to by an indexed getter.
    iviews
      :: (Is k A_Getter,  is `HasSingleIndex` i)
      => Optic' k is s a -> (i -> a -> r) -> s -> r
    iviews :: forall k (is :: IxList) i s a r.
    (Is k A_Getter, HasSingleIndex is i) =>
    Optic' k is s a -> (i -> a -> r) -> s -> r
    iviews Optic' k is s a
    o = \i -> a -> r
    f ->
      IxForget r (i -> i) s s -> (i -> i) -> s -> r
    forall r i a b. IxForget r i a b -> i -> a -> r
    runIxForget (Optic A_Getter is s s a a
    -> Optic_ A_Getter (IxForget 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 @A_Getter Optic' k is s a
    o) ((i -> a -> r) -> IxForget r i a a
    forall r i a b. (i -> a -> r) -> IxForget r i a b
    IxForget i -> a -> r
    f)) i -> i
    forall a. a -> a
    id
    {-# INLINE iviews #-}