    -- |
    -- Module: Optics.Coerce
    -- Description: Operators to 'coerce' the type parameters of 'Optic'.
    --
    -- This module defines operations to 'coerce' the type parameters of optics to
    -- a representationally equal type.  For example, if we have
    --
    -- > newtype MkInt = MkInt Int
    --
    -- and
    --
    -- > l :: Lens' S Int
    --
    -- then
    --
    -- > coerceA @Int @MkInt l :: Lens' S MkInt
    --
    module Optics.Coerce
      ( coerceS
      , coerceT
      , coerceA
      , coerceB
      ) where

    import Data.Coerce

    import Data.Profunctor.Indexed

    import Optics.Internal.Optic

    -- | Lift 'coerce' to the @s@ parameter of an optic.
    coerceS
      :: Coercible s s'
      => Optic k is s  t a b
      -> Optic k is s' t a b
    coerceS :: forall s s' k (is :: IxList) t a b.
    Coercible s s' =>
    Optic k is s t a b -> Optic k is s' t a b
    coerceS = \(Optic forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o) -> (forall (p :: * -> * -> * -> *) i.
     Profunctor p =>
     Optic_ k p i (Curry is i) s' t a b)
    -> Optic k is s' t a b
    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 (Curry is i) s t -> p (Curry is i) s' t
    forall a b (p :: * -> * -> * -> *) i c.
    (Coercible a b, Profunctor p) =>
    p i a c -> p i b c
    lcoerce (p (Curry is i) s t -> p (Curry is i) s' t)
    -> (p i a b -> p (Curry is i) s t)
    -> p i a b
    -> p (Curry is i) s' t
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . p i a b -> p (Curry is i) s t
    forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o)
    {-# INLINE coerceS #-}

    -- | Lift 'coerce' to the @t@ parameter of an optic.
    coerceT
      :: Coercible t t'
      => Optic k is s t  a b
      -> Optic k is s t' a b
    coerceT :: forall t t' k (is :: IxList) s a b.
    Coercible t t' =>
    Optic k is s t a b -> Optic k is s t' a b
    coerceT = \(Optic forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o) -> (forall (p :: * -> * -> * -> *) i.
     Profunctor p =>
     Optic_ k p i (Curry is i) s t' a b)
    -> Optic k is s t' a b
    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 (Curry is i) s t -> p (Curry is i) s t'
    forall a b (p :: * -> * -> * -> *) i c.
    (Coercible a b, Profunctor p) =>
    p i c a -> p i c b
    rcoerce (p (Curry is i) s t -> p (Curry is i) s t')
    -> (p i a b -> p (Curry is i) s t)
    -> p i a b
    -> p (Curry is i) s t'
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . p i a b -> p (Curry is i) s t
    forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o)
    {-# INLINE coerceT #-}

    -- | Lift 'coerce' to the @a@ parameter of an optic.
    coerceA
      :: Coercible a a'
      => Optic k is s t a  b
      -> Optic k is s t a' b
    coerceA :: forall a a' k (is :: IxList) s t b.
    Coercible a a' =>
    Optic k is s t a b -> Optic k is s t a' b
    coerceA = \(Optic forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o) -> (forall (p :: * -> * -> * -> *) i.
     Profunctor p =>
     Optic_ k p i (Curry is i) s t a' b)
    -> Optic k is s t a' b
    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 (Optic__ p i (Curry is i) s t a b
    forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o Optic__ p i (Curry is i) s t a b
    -> (p i a' b -> p i a b) -> p i a' b -> p (Curry is i) s t
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . p i a' b -> p i a b
    forall a b (p :: * -> * -> * -> *) i c.
    (Coercible a b, Profunctor p) =>
    p i a c -> p i b c
    lcoerce)
    {-# INLINE coerceA #-}

    -- | Lift 'coerce' to the @b@ parameter of an optic.
    coerceB
      :: Coercible b b'
      => Optic k is s t a b
      -> Optic k is s t a b'
    coerceB :: forall b b' k (is :: IxList) s t a.
    Coercible b b' =>
    Optic k is s t a b -> Optic k is s t a b'
    coerceB = \(Optic forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o) -> (forall (p :: * -> * -> * -> *) i.
     Profunctor p =>
     Optic_ k p i (Curry is i) s t a b')
    -> Optic k is s t a b'
    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 (Optic__ p i (Curry is i) s t a b
    forall (p :: * -> * -> * -> *) i.
    Profunctor p =>
    Optic_ k p i (Curry is i) s t a b
    o Optic__ p i (Curry is i) s t a b
    -> (p i a b' -> p i a b) -> p i a b' -> p (Curry is i) s t
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . p i a b' -> p i a b
    forall a b (p :: * -> * -> * -> *) i c.
    (Coercible a b, Profunctor p) =>
    p i c a -> p i c b
    rcoerce)
    {-# INLINE coerceB #-}