{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE RankNTypes #-}
{-# LANGUAGE ScopedTypeVariables #-}
{-# LANGUAGE TypeApplications #-}
module Optics.VL
(
IsoVL
, IsoVL'
, isoVL
, toIsoVL
, withIsoVL
, PrismVL
, PrismVL'
, prismVL
, toPrismVL
, withPrismVL
, LensVL
, LensVL'
, lensVL
, toLensVL
, withLensVL
, IxLensVL
, IxLensVL'
, ilensVL
, toIxLensVL
, withIxLensVL
, AffineTraversalVL
, AffineTraversalVL'
, atraversalVL
, atraverseOf
, IxAffineTraversalVL
, IxAffineTraversalVL'
, iatraversalVL
, iatraverseOf
, TraversalVL
, TraversalVL'
, traversalVL
, traverseOf
, IxTraversalVL
, IxTraversalVL'
, itraversalVL
, itraverseOf
) where
import Data.Coerce
import Data.Functor.Identity
import Data.Profunctor.Indexed ((.#), (#.))
import qualified Data.Profunctor as P
import qualified Data.Profunctor.Indexed as IP
import Optics.Internal.Optic
import Optics.Core
newtype WrappedIxProfunctor p i a b =
WrapIxProfunctor { unwrapIxProfunctor :: p i a b }
instance IP.Profunctor p => P.Profunctor (WrappedIxProfunctor p i) where
dimap f g (WrapIxProfunctor piab) = WrapIxProfunctor (IP.dimap f g piab)
lmap f (WrapIxProfunctor piab) = WrapIxProfunctor (IP.lmap f piab)
rmap g (WrapIxProfunctor piab) = WrapIxProfunctor (IP.rmap g piab)
{-# INLINE dimap #-}
{-# INLINE lmap #-}
{-# INLINE rmap #-}
instance IP.Choice p => P.Choice (WrappedIxProfunctor p i) where
left' (WrapIxProfunctor piab) = WrapIxProfunctor (IP.left' piab)
right' (WrapIxProfunctor piab) = WrapIxProfunctor (IP.right' piab)
{-# INLINE left' #-}
{-# INLINE right' #-}
newtype WrappedProfunctor p f i a b =
WrapProfunctor { unwrapProfunctor :: p a (f b) }
instance (P.Profunctor p, Functor f) => IP.Profunctor (WrappedProfunctor p f) where
dimap f g (WrapProfunctor pafb) = WrapProfunctor (P.dimap f (fmap g) pafb)
lmap f (WrapProfunctor pafb) = WrapProfunctor (P.lmap f pafb)
rmap g (WrapProfunctor pafb) = WrapProfunctor (P.rmap (fmap g) pafb)
{-# INLINE dimap #-}
{-# INLINE lmap #-}
{-# INLINE rmap #-}
lcoerce' = IP.lmap coerce
rcoerce' = IP.rmap coerce
{-# INLINE lcoerce' #-}
{-# INLINE rcoerce' #-}
instance (P.Choice p, Applicative f) => IP.Choice (WrappedProfunctor p f) where
left' (WrapProfunctor pafb) =
WrapProfunctor (P.rmap (either (fmap Left) (pure . Right)) (P.left' pafb))
right' (WrapProfunctor pafb) =
WrapProfunctor (P.rmap (either (pure . Left) (fmap Right)) (P.right' pafb))
{-# INLINE left' #-}
{-# INLINE right' #-}
type IsoVL s t a b =
forall p f. (P.Profunctor p, Functor f) => p a (f b) -> p s (f t)
type IsoVL' s a = IsoVL s s a a
isoVL :: forall s t a b. IsoVL s t a b -> Iso s t a b
isoVL f = Optic $ IP.rcoerce @(Identity t) @t
. (unwrapIxProfunctor #. f .# WrapIxProfunctor)
. IP.rcoerce @b @(Identity b)
{-# INLINE isoVL #-}
toIsoVL :: Is k An_Iso => Optic k is s t a b -> IsoVL s t a b
toIsoVL o = unwrapProfunctor #. getOptic (castOptic @An_Iso o) .# WrapProfunctor
{-# INLINE toIsoVL #-}
withIsoVL
:: Is k An_Iso
=> Optic k is s t a b
-> (IsoVL s t a b -> r)
-> r
withIsoVL o k = k (toIsoVL o)
{-# INLINE withIsoVL #-}
type PrismVL s t a b =
forall p f. (P.Choice p, Applicative f) => p a (f b) -> p s (f t)
type PrismVL' s a = PrismVL s s a a
prismVL :: forall s t a b. PrismVL s t a b -> Prism s t a b
prismVL f = Optic $ IP.rcoerce @(Identity t) @t
. (unwrapIxProfunctor #. f .# WrapIxProfunctor)
. IP.rcoerce @b @(Identity b)
{-# INLINE prismVL #-}
toPrismVL :: Is k A_Prism => Optic k is s t a b -> PrismVL s t a b
toPrismVL o = unwrapProfunctor #. getOptic (castOptic @A_Prism o) .# WrapProfunctor
{-# INLINE toPrismVL #-}
withPrismVL
:: Is k A_Prism
=> Optic k is s t a b
-> (PrismVL s t a b -> r)
-> r
withPrismVL o k = k (toPrismVL o)
{-# INLINE withPrismVL #-}