-- |
-- Module: Optics.IxAffineTraversal
-- Description: An indexed version of an 'Optics.AffineTraversal.AffineTraversal'.
--
-- An 'IxAffineTraversal' is an indexed version of an
-- 'Optics.AffineTraversal.AffineTraversal'.  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.IxAffineTraversal
  (
  -- * Formation
    IxAffineTraversal
  , IxAffineTraversal'

  -- * Introduction
  , iatraversal

  -- * Elimination
  -- | An 'IxAffineTraversal' is in particular an
  -- 'Optics.IxAffineFold.IxAffineFold' and an 'Optics.IxSetter.IxSetter',
  -- therefore you can specialise types to obtain:
  --
  -- @
  -- 'Optics.IxAffineFold.ipreview' :: 'IxAffineTraversal' i s t a b -> s -> Maybe (i, a)
  -- @
  --
  -- @
  -- 'Optics.IxSetter.iover'    :: 'IxAffineTraversal' i s t a b -> (i -> a -> b) -> s -> t
  -- 'Optics.IxSetter.iset'     :: 'IxAffineTraversal' i s t a b -> (i      -> b) -> s -> t
  -- @

  -- * Combinators
  , unsafeFilteredBy

  -- * Additional introduction forms
  , ignored

  -- * Subtyping
  , An_AffineTraversal

  -- * van Laarhoven encoding
  , IxAffineTraversalVL
  , IxAffineTraversalVL'
  , iatraversalVL
  , iatraverseOf
  ) where

import Data.Profunctor.Indexed

import Optics.AffineFold
import Optics.Internal.Indexed
import Optics.Internal.Optic
import Optics.Internal.Utils

-- | Type synonym for a type-modifying indexed affine traversal.
type IxAffineTraversal i s t a b = Optic An_AffineTraversal (WithIx i) s t a b

-- | Type synonym for a type-preserving indexed affine traversal.
type IxAffineTraversal' i s a = Optic' An_AffineTraversal (WithIx i) s a

-- | Type synonym for a type-modifying van Laarhoven indexed affine traversal.
--
-- Note: this isn't exactly van Laarhoven representation as there is no
-- @Pointed@ class (which would be a superclass of 'Applicative' that contains
-- 'pure' but not '<*>'). You can interpret the first argument as a dictionary
-- of @Pointed@ that supplies the @point@ function (i.e. the implementation of
-- 'pure').
--
type IxAffineTraversalVL i s t a b =
  forall f. Functor f => (forall r. r -> f r) -> (i -> a -> f b) -> s -> f t

-- | Type synonym for a type-preserving van Laarhoven indexed affine traversal.
type IxAffineTraversalVL' i s a = IxAffineTraversalVL i s s a a

-- | Build an indexed affine traversal from a matcher and an updater.
--
-- If you want to build an 'IxAffineTraversal' from the van Laarhoven
-- representation, use 'iatraversalVL'.
iatraversal :: (s -> Either t (i, a)) -> (s -> b -> t) -> IxAffineTraversal i s t a b
iatraversal :: forall s t i a b.
(s -> Either t (i, a))
-> (s -> b -> t) -> IxAffineTraversal i s t a b
iatraversal s -> Either t (i, a)
match s -> b -> t
update = forall i s t a b.
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL forall a b. (a -> b) -> a -> b
$ \forall r. r -> f r
point i -> a -> f b
f s
s ->
  forall a c b. (a -> c) -> (b -> c) -> Either a b -> c
either forall r. r -> f r
point (\(i, a)
a -> s -> b -> t
update s
s forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
<$> forall a b c. (a -> b -> c) -> (a, b) -> c
uncurry' i -> a -> f b
f (i, a)
a) (s -> Either t (i, a)
match s
s)
{-# INLINE iatraversal #-}

-- | Build an indexed affine traversal from the van Laarhoven representation.
iatraversalVL :: IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL :: forall i s t a b.
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL IxAffineTraversalVL i s t a b
f = 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 a b s t j.
Visiting p =>
(forall (f :: * -> *).
 Functor f =>
 (forall r. r -> f r) -> (i -> a -> f b) -> s -> f t)
-> p j a b -> p (i -> j) s t
ivisit IxAffineTraversalVL i s t a b
f)
{-# INLINE iatraversalVL #-}

-- | Traverse over the target of an 'IxAffineTraversal' and compute a
-- 'Functor'-based answer.
--
-- @since 0.3
iatraverseOf
  :: (Is k An_AffineTraversal, Functor f, is `HasSingleIndex` i)
  => Optic k is s t a b
  -> (forall r. r -> f r) -> (i -> a -> f b) -> s -> f t
iatraverseOf :: forall k (f :: * -> *) (is :: IxList) i s t a b.
(Is k An_AffineTraversal, Functor f, HasSingleIndex is i) =>
Optic k is s t a b
-> (forall r. r -> f r) -> (i -> a -> f b) -> s -> f t
iatraverseOf Optic k is s t a b
o forall r. r -> f r
point = \i -> a -> f b
f ->
  forall (f :: * -> *) i a b. IxStarA f i a b -> i -> a -> f b
runIxStarA (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 @An_AffineTraversal Optic k is s t a b
o) (forall (f :: * -> *) i a b.
(forall r. r -> f r) -> (i -> a -> f b) -> IxStarA f i a b
IxStarA forall r. r -> f r
point i -> a -> f b
f)) forall a. a -> a
id
{-# INLINE iatraverseOf #-}

-- | Obtain a potentially empty 'IxAffineTraversal' by taking the element from
-- another 'AffineFold' and using it as an index.
--
-- -- /Note:/ This is /not/ a legal 'Optics.IxTraversal.IxTraversal', unless you
-- are very careful not to invalidate the predicate on the target (see
-- 'Optics.AffineTraversal.unsafeFiltered' for more details).
--
-- @since 0.3
unsafeFilteredBy
  :: Is k An_AffineFold
  => Optic' k is a i
  -> IxAffineTraversal' i a a
unsafeFilteredBy :: forall k (is :: IxList) a i.
Is k An_AffineFold =>
Optic' k is a i -> IxAffineTraversal' i a a
unsafeFilteredBy Optic' k is a i
p = forall i s t a b.
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL forall a b. (a -> b) -> a -> b
$ \forall r. r -> f r
point i -> a -> f a
f a
s -> case forall k (is :: IxList) s a.
Is k An_AffineFold =>
Optic' k is s a -> s -> Maybe a
preview Optic' k is a i
p a
s of
  Just i
i  -> i -> a -> f a
f i
i a
s
  Maybe i
Nothing -> forall r. r -> f r
point a
s
{-# INLINE unsafeFilteredBy #-}

-- | This is the trivial empty 'IxAffineTraversal', i.e. the optic that targets
-- no substructures.
--
-- This is the identity element when a 'Optics.Fold.Fold',
-- 'Optics.AffineFold.AffineFold', 'Optics.IxFold.IxFold',
-- 'Optics.IxAffineFold.IxAffineFold', 'Optics.Traversal.Traversal' or
-- 'Optics.IxTraversal.IxTraversal' is viewed as a monoid.
--
-- >>> 6 & ignored %~ absurd
-- 6
ignored :: IxAffineTraversal i s s a b
ignored :: forall i s a b. IxAffineTraversal i s s a b
ignored = forall i s t a b.
IxAffineTraversalVL i s t a b -> IxAffineTraversal i s t a b
iatraversalVL forall a b. (a -> b) -> a -> b
$ \forall r. r -> f r
point i -> a -> f b
_ -> forall r. r -> f r
point
{-# INLINE ignored #-}

-- $setup
-- >>> import Optics.Core
-- >>> import Data.Void (absurd)