-- |
-- 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 :: 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 :: 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 :: 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 :: 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 #-}