optics-core-0.3: src/Optics/IxAffineTraversal.hs
-- |
-- 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 match update = iatraversalVL $ \point f s ->
either point (\a -> update s <$> uncurry' f a) (match 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 f = Optic (ivisit 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 o point = \f ->
runIxStarA (getOptic (castOptic @An_AffineTraversal o) (IxStarA point f)) 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 p = iatraversalVL $ \point f s -> case preview p s of
Just i -> f i s
Nothing -> point 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' or
-- 'Optics.IxAffineFold.IxAffineFold' is viewed as a monoid.
--
-- >>> 6 & ignored %~ absurd
-- 6
ignored :: IxAffineTraversal i s s a b
ignored = iatraversalVL $ \point _ -> point
-- $setup
-- >>> import Optics.Core
-- >>> import Data.Void (absurd)