-- |
-- 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 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 (forall a b (p :: * -> * -> * -> *) i c.
(Coercible a b, Profunctor p) =>
p i a c -> p i b c
lcoerce forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 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 (forall a b (p :: * -> * -> * -> *) i c.
(Coercible a b, Profunctor p) =>
p i c a -> p i c b
rcoerce forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 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 (forall (p :: * -> * -> * -> *) i.
Profunctor p =>
Optic_ k p i (Curry is i) s t a b
o forall b c a. (b -> c) -> (a -> b) -> a -> c
. 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 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 (forall (p :: * -> * -> * -> *) i.
Profunctor p =>
Optic_ k p i (Curry is i) s t a b
o forall b c a. (b -> c) -> (a -> b) -> a -> c
. forall a b (p :: * -> * -> * -> *) i c.
(Coercible a b, Profunctor p) =>
p i c a -> p i c b
rcoerce)
{-# INLINE coerceB #-}