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

  -- * Introduction
  , iafolding

  -- * Elimination
  , ipreview
  , ipreviews

  -- * Computation
  -- |
  --
  -- @
  -- 'ipreview' ('iafolding' f) ≡ f
  -- @

  -- * Semigroup structure
  , iafailing

  -- * Subtyping
  , An_AffineFold
  ) where

import Data.Profunctor.Indexed

import Optics.AffineFold
import Optics.Internal.Bi
import Optics.Internal.Indexed
import Optics.Internal.Optic

-- | Type synonym for an indexed affine fold.
type IxAffineFold i s a = Optic' An_AffineFold (WithIx i) s a

-- | Retrieve the value along with its index targeted by an 'IxAffineFold'.
ipreview
  :: (Is k An_AffineFold, is `HasSingleIndex` i)
  => Optic' k is s a
  -> s -> Maybe (i, a)
ipreview :: Optic' k is s a -> s -> Maybe (i, a)
ipreview o :: Optic' k is s a
o = Optic' k is s a -> (i -> a -> (i, a)) -> s -> Maybe (i, a)
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (a :: OpticKind) (r :: OpticKind).
(Is k An_AffineFold, HasSingleIndex is i) =>
Optic' k is s a -> (i -> a -> r) -> s -> Maybe r
ipreviews Optic' k is s a
o (,)
{-# INLINE ipreview #-}

-- | Retrieve a function of the value and its index targeted by an
-- 'IxAffineFold'.
ipreviews
  :: (Is k An_AffineFold, is `HasSingleIndex` i)
  => Optic' k is s a
  -> (i -> a -> r) -> s -> Maybe r
ipreviews :: Optic' k is s a -> (i -> a -> r) -> s -> Maybe r
ipreviews o :: Optic' k is s a
o = \f :: i -> a -> r
f -> IxForgetM r (i -> i) s s -> (i -> i) -> s -> Maybe r
forall (r :: OpticKind) (i :: OpticKind) (a :: OpticKind)
       (b :: OpticKind).
IxForgetM r i a b -> i -> a -> Maybe r
runIxForgetM
  (Optic An_AffineFold is s s a a
-> forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
          (i :: OpticKind).
   (Profunctor p, Constraints An_AffineFold p) =>
   Optic__ p i (Curry is i) s s a a
forall (k :: OpticKind) (is :: IxList) (s :: OpticKind)
       (t :: OpticKind) (a :: OpticKind) (b :: OpticKind).
Optic k is s t a b
-> forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
          (i :: OpticKind).
   (Profunctor p, Constraints k p) =>
   Optic__ p i (Curry is i) s t a b
getOptic (Optic' k is s a -> Optic An_AffineFold is s s a a
forall (destKind :: OpticKind) (srcKind :: OpticKind)
       (is :: IxList) (s :: OpticKind) (t :: OpticKind) (a :: OpticKind)
       (b :: OpticKind).
Is srcKind destKind =>
Optic srcKind is s t a b -> Optic destKind is s t a b
castOptic @An_AffineFold Optic' k is s a
o) (IxForgetM r i a a -> IxForgetM r (i -> i) s s)
-> ((i -> a -> Maybe r) -> IxForgetM r i a a)
-> (i -> a -> Maybe r)
-> IxForgetM r (i -> i) s s
forall (b :: OpticKind) (c :: OpticKind) (a :: OpticKind).
(b -> c) -> (a -> b) -> a -> c
. (i -> a -> Maybe r) -> IxForgetM r i a a
forall (r :: OpticKind) (i :: OpticKind) (a :: OpticKind)
       (b :: OpticKind).
(i -> a -> Maybe r) -> IxForgetM r i a b
IxForgetM ((i -> a -> Maybe r) -> IxForgetM r (i -> i) s s)
-> (i -> a -> Maybe r) -> IxForgetM r (i -> i) s s
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ \i :: i
i -> r -> Maybe r
forall (a :: OpticKind). a -> Maybe a
Just (r -> Maybe r) -> (a -> r) -> a -> Maybe r
forall (b :: OpticKind) (c :: OpticKind) (a :: OpticKind).
(b -> c) -> (a -> b) -> a -> c
. i -> a -> r
f i
i)
  i -> i
forall (a :: OpticKind). a -> a
id
{-# INLINE ipreviews #-}

-- | Create an 'IxAffineFold' from a partial function.
iafolding :: (s -> Maybe (i, a)) -> IxAffineFold i s a
iafolding :: (s -> Maybe (i, a)) -> IxAffineFold i s a
iafolding g :: s -> Maybe (i, a)
g = (forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
        (i :: OpticKind).
 Profunctor p =>
 Optic_ An_AffineFold p i (Curry (WithIx i) i) s s a a)
-> IxAffineFold i s a
forall (k :: OpticKind) (is :: IxList) (s :: OpticKind)
       (t :: OpticKind) (a :: OpticKind) (b :: OpticKind).
(forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
        (i :: OpticKind).
 (Profunctor p, Constraints k p) =>
 Optic__ p i (Curry is i) s t a b)
-> Optic k is s t a b
Optic
  ((forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
         (i :: OpticKind).
  Profunctor p =>
  Optic_ An_AffineFold p i (Curry (WithIx i) i) s s a a)
 -> IxAffineFold i s a)
-> (forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
           (i :: OpticKind).
    Profunctor p =>
    Optic_ An_AffineFold p i (Curry (WithIx i) i) s s a a)
-> IxAffineFold i s a
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ (forall (f :: OpticKind -> OpticKind).
 Functor f =>
 (forall (r :: OpticKind). r -> f r) -> (i -> a -> f s) -> s -> f s)
-> p i a s -> p (i -> i) s s
forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
       (i :: OpticKind) (a :: OpticKind) (b :: OpticKind) (s :: OpticKind)
       (t :: OpticKind) (j :: OpticKind).
Visiting p =>
(forall (f :: OpticKind -> OpticKind).
 Functor f =>
 (forall (r :: OpticKind). r -> f r) -> (i -> a -> f b) -> s -> f t)
-> p j a b -> p (i -> j) s t
ivisit (\point :: forall (r :: OpticKind). r -> f r
point f :: i -> a -> f s
f s :: s
s -> f s -> ((i, a) -> f s) -> Maybe (i, a) -> f s
forall (b :: OpticKind) (a :: OpticKind).
b -> (a -> b) -> Maybe a -> b
maybe (s -> f s
forall (r :: OpticKind). r -> f r
point s
s) ((i -> a -> f s) -> (i, a) -> f s
forall (a :: OpticKind) (b :: OpticKind) (c :: OpticKind).
(a -> b -> c) -> (a, b) -> c
uncurry i -> a -> f s
f) (Maybe (i, a) -> f s) -> Maybe (i, a) -> f s
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ s -> Maybe (i, a)
g s
s)
  (p i a s -> p (i -> i) s s)
-> (p i a a -> p i a s) -> p i a a -> p (i -> i) s s
forall (b :: OpticKind) (c :: OpticKind) (a :: OpticKind).
(b -> c) -> (a -> b) -> a -> c
. p i a a -> p i a s
forall (p :: OpticKind -> OpticKind -> OpticKind -> OpticKind)
       (i :: OpticKind) (c :: OpticKind) (a :: OpticKind)
       (b :: OpticKind).
(Profunctor p, Bicontravariant p) =>
p i c a -> p i c b
rphantom
{-# INLINE iafolding #-}

-- | Try the first 'IxAffineFold'. If it returns no entry, try the second one.
--
-- /Note:/ There is no 'Optics.IxFold.isumming' equivalent, because @iasumming = iafailing@.
iafailing
  :: (Is k An_AffineFold, Is l An_AffineFold,
      is1 `HasSingleIndex` i, is2 `HasSingleIndex` i)
  => Optic' k is1 s a
  -> Optic' l is2 s a
  -> IxAffineFold i s a
iafailing :: Optic' k is1 s a -> Optic' l is2 s a -> IxAffineFold i s a
iafailing a :: Optic' k is1 s a
a b :: Optic' l is2 s a
b = Optic An_AffineFold NoIx s s a a
-> IxAffineFold i s a -> IxAffineFold i s a
forall (is :: IxList) (i :: OpticKind) (k :: OpticKind)
       (s :: OpticKind) (t :: OpticKind) (a :: OpticKind)
       (b :: OpticKind).
HasSingleIndex is i =>
Optic k NoIx s t a b -> Optic k is s t a b -> Optic k is s t a b
conjoined (Optic' k is1 s a
-> Optic' l is2 s a -> Optic An_AffineFold NoIx s s a a
forall (k :: OpticKind) (l :: OpticKind) (is :: IxList)
       (s :: OpticKind) (a :: OpticKind) (js :: IxList).
(Is k An_AffineFold, Is l An_AffineFold) =>
Optic' k is s a -> Optic' l js s a -> AffineFold s a
afailing Optic' k is1 s a
a Optic' l is2 s a
b) (IxAffineFold i s a -> IxAffineFold i s a)
-> IxAffineFold i s a -> IxAffineFold i s a
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ (s -> Maybe (i, a)) -> IxAffineFold i s a
forall (s :: OpticKind) (i :: OpticKind) (a :: OpticKind).
(s -> Maybe (i, a)) -> IxAffineFold i s a
iafolding ((s -> Maybe (i, a)) -> IxAffineFold i s a)
-> (s -> Maybe (i, a)) -> IxAffineFold i s a
forall (a :: OpticKind) b. (a -> b) -> a -> b
$ \s :: s
s ->
  Maybe (i, a)
-> ((i, a) -> Maybe (i, a)) -> Maybe (i, a) -> Maybe (i, a)
forall (b :: OpticKind) (a :: OpticKind).
b -> (a -> b) -> Maybe a -> b
maybe (Optic' l is2 s a -> s -> Maybe (i, a)
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (a :: OpticKind).
(Is k An_AffineFold, HasSingleIndex is i) =>
Optic' k is s a -> s -> Maybe (i, a)
ipreview Optic' l is2 s a
b s
s) (i, a) -> Maybe (i, a)
forall (a :: OpticKind). a -> Maybe a
Just (Optic' k is1 s a -> s -> Maybe (i, a)
forall (k :: OpticKind) (is :: IxList) (i :: OpticKind)
       (s :: OpticKind) (a :: OpticKind).
(Is k An_AffineFold, HasSingleIndex is i) =>
Optic' k is s a -> s -> Maybe (i, a)
ipreview Optic' k is1 s a
a s
s)
infixl 3 `iafailing` -- Same as (<|>)
{-# INLINE iafailing #-}