-- | -- Module: Optics.IxLens -- Description: An indexed version of a 'Optics.Lens.Lens'. -- -- An 'IxLens' is an indexed version of a 'Optics.Lens.Lens'. 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.IxLens ( -- * Formation IxLens , IxLens' -- * Introduction , ilens -- * Elimination -- | An 'IxLens' is in particular an 'Optics.IxGetter.IxGetter' and an -- 'Optics.IxSetter.IxSetter', therefore you can specialise types to obtain: -- -- @ -- 'Optics.IxGetter.iview' :: 'IxLens' i s t a b -> s -> (i, a) -- @ -- -- @ -- 'Optics.IxSetter.iover' :: 'IxLens' i s t a b -> (i -> a -> b) -> s -> t -- 'Optics.IxSetter.iset' :: 'IxLens' i s t a b -> (i -> b) -> s -> t -- @ -- * Additional introduction forms , chosen , devoid , ifst , isnd -- * Subtyping , A_Lens -- * van Laarhoven encoding , IxLensVL , IxLensVL' , ilensVL , toIxLensVL , withIxLensVL ) where import Data.Void import Data.Profunctor.Indexed import Optics.Internal.Indexed import Optics.Internal.Optic import Optics.Internal.Utils -- | Type synonym for a type-modifying indexed lens. type IxLens i s t a b = Optic A_Lens (WithIx i) s t a b -- | Type synonym for a type-preserving indexed lens. type IxLens' i s a = Optic' A_Lens (WithIx i) s a -- | Type synonym for a type-modifying van Laarhoven indexed lens. type IxLensVL i s t a b = forall f. Functor f => (i -> a -> f b) -> s -> f t -- | Type synonym for a type-preserving van Laarhoven indexed lens. type IxLensVL' i s a = IxLensVL i s s a a -- | Build an indexed lens from a getter and a setter. -- -- If you want to build an 'IxLens' from the van Laarhoven representation, use -- 'ilensVL'. ilens :: (s -> (i, a)) -> (s -> b -> t) -> IxLens i s t a b ilens get set = ilensVL $ \f s -> set s <$> uncurry' f (get s) {-# INLINE ilens #-} -- | Build an indexed lens from the van Laarhoven representation. ilensVL :: IxLensVL i s t a b -> IxLens i s t a b ilensVL f = Optic (ilinear f) {-# INLINE ilensVL #-} -- | Convert an indexed lens to its van Laarhoven representation. toIxLensVL :: (Is k A_Lens, is `HasSingleIndex` i) => Optic k is s t a b -> IxLensVL i s t a b toIxLensVL o = \f -> runIxStar (getOptic (castOptic @A_Lens o) (IxStar f)) id {-# INLINE toIxLensVL #-} -- | Work with an indexed lens in the van Laarhoven representation. withIxLensVL :: (Is k A_Lens, is `HasSingleIndex` i) => Optic k is s t a b -> (IxLensVL i s t a b -> r) -> r withIxLensVL o k = k (toIxLensVL o) {-# INLINE withIxLensVL #-} ---------------------------------------- -- Lenses -- | Focus on both sides of an 'Either'. chosen :: IxLens (Either () ()) (Either a a) (Either b b) a b chosen = ilensVL $ \f -> \case Left a -> Left <$> f (Left ()) a Right a -> Right <$> f (Right ()) a {-# INLINE chosen #-} -- | There is an indexed field for every type in the 'Void'. -- -- >>> set (mapped % devoid) 1 [] -- [] -- -- >>> over (_Just % devoid) abs Nothing -- Nothing -- devoid :: IxLens' i Void a devoid = ilens absurd const {-# INLINE devoid #-} -- | Indexed '_1' with other half of a pair as an index. -- -- See 'isnd' for examples. -- -- @since 0.4 -- ifst :: IxLens i (a, i) (b, i) a b ifst = ilens (\(a, i) -> (i, a)) (\(_,i) b -> (b, i)) -- | Indexed '_2' with other half of a pair as an index. -- Specialized version of 'itraversed' to pairs, which can be 'IxLens'. -- -- >>> iview isnd ('a', True) -- ('a',True) -- -- That is not possible with 'itraversed', because it is an 'IxTraversal'. -- -- >>> :t itraversed :: IxTraversal i (i, a) (i, b) a b -- itraversed :: IxTraversal i (i, a) (i, b) a b -- :: IxTraversal i (i, a) (i, b) a b -- -- @since 0.4 -- isnd :: IxLens i (i, a) (i, b) a b isnd = ilens id (\(i,_) b -> (i, b)) -- $setup -- >>> import Optics.Core