{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE DefaultSignatures #-}
{-# LANGUAGE UndecidableInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
#ifdef TRUSTWORTHY
{-# LANGUAGE Trustworthy #-}
#endif
#if __GLASGOW_HASKELL__ >= 711
{-# OPTIONS_GHC -fno-warn-redundant-constraints #-}
#endif
#ifndef MIN_VERSION_containers
#define MIN_VERSION_containers(x,y,z) 1
#endif
module Control.Lens.Indexed
(
Indexable(..)
, Conjoined(..)
, Indexed(..)
, (<.), (<.>), (.>)
, selfIndex
, reindexed
, icompose
, indexing
, indexing64
, FunctorWithIndex(..)
, FoldableWithIndex(..)
, iany
, iall
, inone, none
, itraverse_
, ifor_
, imapM_
, iforM_
, iconcatMap
, ifind
, ifoldrM
, ifoldlM
, itoList
, withIndex
, asIndex
, indices
, index
, TraversableWithIndex(..)
, ifor
, imapM
, iforM
, imapAccumR
, imapAccumL
, ifoldMapBy
, ifoldMapByOf
) where
import Control.Applicative
import Control.Applicative.Backwards
import Control.Comonad.Cofree
import Control.Comonad.Trans.Traced
import Control.Monad (void, liftM)
import Control.Monad.Trans.Identity
import Control.Monad.Trans.Reader
import Control.Monad.Trans.State.Lazy as Lazy
import Control.Monad.Free
import Control.Lens.Fold
import Control.Lens.Getter
import Control.Lens.Internal.Fold
import Control.Lens.Internal.Indexed
import Control.Lens.Internal.Level
import Control.Lens.Internal.Magma
import Control.Lens.Setter
import Control.Lens.Traversal
import Control.Lens.Type
import Data.Array (Array)
import qualified Data.Array as Array
import Data.Foldable
import Data.Functor.Compose
import Data.Functor.Product
import Data.Functor.Reverse
import Data.Hashable
import Data.HashMap.Lazy as HashMap
import Data.IntMap as IntMap
import Data.Ix (Ix)
import Data.List.NonEmpty as NonEmpty
import Data.Map as Map
import Data.Monoid hiding (Product)
import Data.Profunctor.Unsafe
import Data.Sequence hiding ((:<), index)
#if !(MIN_VERSION_containers(0,5,0))
import Data.Traversable (sequenceA)
#endif
import Data.Tree
import Data.Tuple (swap)
import Data.Vector (Vector)
import qualified Data.Vector as V
import Prelude
infixr 9 <.>, <., .>
(<.) :: Indexable i p => (Indexed i s t -> r) -> ((a -> b) -> s -> t) -> p a b -> r
(<.) f g h = f . Indexed $ g . indexed h
{-# INLINE (<.) #-}
(.>) :: (st -> r) -> (kab -> st) -> kab -> r
(.>) = (.)
{-# INLINE (.>) #-}
selfIndex :: Indexable a p => p a fb -> a -> fb
selfIndex f a = indexed f a a
{-# INLINE selfIndex #-}
reindexed :: Indexable j p => (i -> j) -> (Indexed i a b -> r) -> p a b -> r
reindexed ij f g = f . Indexed $ indexed g . ij
{-# INLINE reindexed #-}
(<.>) :: Indexable (i, j) p => (Indexed i s t -> r) -> (Indexed j a b -> s -> t) -> p a b -> r
f <.> g = icompose (,) f g
{-# INLINE (<.>) #-}
icompose :: Indexable p c => (i -> j -> p) -> (Indexed i s t -> r) -> (Indexed j a b -> s -> t) -> c a b -> r
icompose ijk istr jabst cab = istr . Indexed $ \i -> jabst . Indexed $ \j -> indexed cab $ ijk i j
{-# INLINE icompose #-}
indices :: (Indexable i p, Applicative f) => (i -> Bool) -> Optical' p (Indexed i) f a a
indices p f = Indexed $ \i a -> if p i then indexed f i a else pure a
{-# INLINE indices #-}
index :: (Indexable i p, Eq i, Applicative f) => i -> Optical' p (Indexed i) f a a
index j f = Indexed $ \i a -> if j == i then indexed f i a else pure a
{-# INLINE index #-}
class Functor f => FunctorWithIndex i f | f -> i where
imap :: (i -> a -> b) -> f a -> f b
#ifndef HLINT
default imap :: TraversableWithIndex i f => (i -> a -> b) -> f a -> f b
imap = iover itraversed
{-# INLINE imap #-}
#endif
imapped :: IndexedSetter i (f a) (f b) a b
imapped = conjoined mapped (isets imap)
{-# INLINE imapped #-}
class Foldable f => FoldableWithIndex i f | f -> i where
ifoldMap :: Monoid m => (i -> a -> m) -> f a -> m
#ifndef HLINT
default ifoldMap :: (TraversableWithIndex i f, Monoid m) => (i -> a -> m) -> f a -> m
ifoldMap = ifoldMapOf itraversed
{-# INLINE ifoldMap #-}
#endif
ifolded :: IndexedFold i (f a) a
ifolded = conjoined folded $ \f -> coerce . getFolding . ifoldMap (\i -> Folding #. indexed f i)
{-# INLINE ifolded #-}
ifoldr :: (i -> a -> b -> b) -> b -> f a -> b
ifoldr f z t = appEndo (ifoldMap (\i -> Endo #. f i) t) z
{-# INLINE ifoldr #-}
ifoldl :: (i -> b -> a -> b) -> b -> f a -> b
ifoldl f z t = appEndo (getDual (ifoldMap (\i -> Dual #. Endo #. flip (f i)) t)) z
{-# INLINE ifoldl #-}
ifoldr' :: (i -> a -> b -> b) -> b -> f a -> b
ifoldr' f z0 xs = ifoldl f' id xs z0
where f' i k x z = k $! f i x z
{-# INLINE ifoldr' #-}
ifoldl' :: (i -> b -> a -> b) -> b -> f a -> b
ifoldl' f z0 xs = ifoldr f' id xs z0
where f' i x k z = k $! f i z x
{-# INLINE ifoldl' #-}
iany :: FoldableWithIndex i f => (i -> a -> Bool) -> f a -> Bool
iany f = getAny #. ifoldMap (\i -> Any #. f i)
{-# INLINE iany #-}
iall :: FoldableWithIndex i f => (i -> a -> Bool) -> f a -> Bool
iall f = getAll #. ifoldMap (\i -> All #. f i)
{-# INLINE iall #-}
inone :: FoldableWithIndex i f => (i -> a -> Bool) -> f a -> Bool
inone f = not . iany f
{-# INLINE inone #-}
none :: Foldable f => (a -> Bool) -> f a -> Bool
none f = not . Data.Foldable.any f
{-# INLINE none #-}
itraverse_ :: (FoldableWithIndex i t, Applicative f) => (i -> a -> f b) -> t a -> f ()
itraverse_ f = getTraversed #. ifoldMap (\i -> Traversed #. void . f i)
{-# INLINE itraverse_ #-}
ifor_ :: (FoldableWithIndex i t, Applicative f) => t a -> (i -> a -> f b) -> f ()
ifor_ = flip itraverse_
{-# INLINE ifor_ #-}
imapM_ :: (FoldableWithIndex i t, Monad m) => (i -> a -> m b) -> t a -> m ()
imapM_ f = getSequenced #. ifoldMap (\i -> Sequenced #. liftM skip . f i)
{-# INLINE imapM_ #-}
iforM_ :: (FoldableWithIndex i t, Monad m) => t a -> (i -> a -> m b) -> m ()
iforM_ = flip imapM_
{-# INLINE iforM_ #-}
iconcatMap :: FoldableWithIndex i f => (i -> a -> [b]) -> f a -> [b]
iconcatMap = ifoldMap
{-# INLINE iconcatMap #-}
ifind :: FoldableWithIndex i f => (i -> a -> Bool) -> f a -> Maybe (i, a)
ifind p = ifoldr (\i a y -> if p i a then Just (i, a) else y) Nothing
{-# INLINE ifind #-}
ifoldrM :: (FoldableWithIndex i f, Monad m) => (i -> a -> b -> m b) -> b -> f a -> m b
ifoldrM f z0 xs = ifoldl f' return xs z0
where f' i k x z = f i x z >>= k
{-# INLINE ifoldrM #-}
ifoldlM :: (FoldableWithIndex i f, Monad m) => (i -> b -> a -> m b) -> b -> f a -> m b
ifoldlM f z0 xs = ifoldr f' return xs z0
where f' i x k z = f i z x >>= k
{-# INLINE ifoldlM #-}
itoList :: FoldableWithIndex i f => f a -> [(i,a)]
itoList = ifoldr (\i c -> ((i,c):)) []
{-# INLINE itoList #-}
class (FunctorWithIndex i t, FoldableWithIndex i t, Traversable t) => TraversableWithIndex i t | t -> i where
itraverse :: Applicative f => (i -> a -> f b) -> t a -> f (t b)
#ifndef HLINT
default itraverse :: Applicative f => (Int -> a -> f b) -> t a -> f (t b)
itraverse = traversed .# Indexed
{-# INLINE itraverse #-}
#endif
itraversed :: IndexedTraversal i (t a) (t b) a b
itraversed = conjoined traverse (itraverse . indexed)
{-# INLINE itraversed #-}
ifor :: (TraversableWithIndex i t, Applicative f) => t a -> (i -> a -> f b) -> f (t b)
ifor = flip itraverse
{-# INLINE ifor #-}
imapM :: (TraversableWithIndex i t, Monad m) => (i -> a -> m b) -> t a -> m (t b)
imapM f = unwrapMonad #. itraverse (\i -> WrapMonad #. f i)
{-# INLINE imapM #-}
iforM :: (TraversableWithIndex i t, Monad m) => t a -> (i -> a -> m b) -> m (t b)
iforM = flip imapM
{-# INLINE iforM #-}
imapAccumR :: TraversableWithIndex i t => (i -> s -> a -> (s, b)) -> s -> t a -> (s, t b)
imapAccumR f s0 a = swap (Lazy.runState (forwards (itraverse (\i c -> Backwards (Lazy.state (\s -> swap (f i s c)))) a)) s0)
{-# INLINE imapAccumR #-}
imapAccumL :: TraversableWithIndex i t => (i -> s -> a -> (s, b)) -> s -> t a -> (s, t b)
imapAccumL f s0 a = swap (Lazy.runState (itraverse (\i c -> Lazy.state (\s -> swap (f i s c))) a) s0)
{-# INLINE imapAccumL #-}
instance FunctorWithIndex i f => FunctorWithIndex i (Backwards f) where
imap f = Backwards . imap f . forwards
{-# INLINE imap #-}
instance FoldableWithIndex i f => FoldableWithIndex i (Backwards f) where
ifoldMap f = ifoldMap f . forwards
{-# INLINE ifoldMap #-}
instance TraversableWithIndex i f => TraversableWithIndex i (Backwards f) where
itraverse f = fmap Backwards . itraverse f . forwards
{-# INLINE itraverse #-}
instance FunctorWithIndex i f => FunctorWithIndex i (Reverse f) where
imap f = Reverse . imap f . getReverse
{-# INLINE imap #-}
instance FoldableWithIndex i f => FoldableWithIndex i (Reverse f) where
ifoldMap f = getDual . ifoldMap (\i -> Dual #. f i) . getReverse
{-# INLINE ifoldMap #-}
instance TraversableWithIndex i f => TraversableWithIndex i (Reverse f) where
itraverse f = fmap Reverse . forwards . itraverse (\i -> Backwards . f i) . getReverse
{-# INLINE itraverse #-}
instance FunctorWithIndex () Identity where
imap f (Identity a) = Identity (f () a)
{-# INLINE imap #-}
instance FoldableWithIndex () Identity where
ifoldMap f (Identity a) = f () a
{-# INLINE ifoldMap #-}
instance TraversableWithIndex () Identity where
itraverse f (Identity a) = Identity <$> f () a
{-# INLINE itraverse #-}
instance FunctorWithIndex k ((,) k) where
imap f (k,a) = (k, f k a)
{-# INLINE imap #-}
instance FoldableWithIndex k ((,) k) where
ifoldMap = uncurry
{-# INLINE ifoldMap #-}
instance TraversableWithIndex k ((,) k) where
itraverse f (k, a) = (,) k <$> f k a
{-# INLINE itraverse #-}
instance FunctorWithIndex Int []
instance FoldableWithIndex Int []
instance TraversableWithIndex Int [] where
itraversed = traversed
{-# INLINE itraversed #-}
instance FunctorWithIndex Int NonEmpty
instance FoldableWithIndex Int NonEmpty
instance TraversableWithIndex Int NonEmpty where
itraverse = itraverseOf traversed
{-# INLINE itraverse #-}
instance FunctorWithIndex () Maybe where
imap f = fmap (f ())
{-# INLINE imap #-}
instance FoldableWithIndex () Maybe where
ifoldMap f = foldMap (f ())
{-# INLINE ifoldMap #-}
instance TraversableWithIndex () Maybe where
itraverse f = traverse (f ())
{-# INLINE itraverse #-}
instance FunctorWithIndex Int Seq
instance FoldableWithIndex Int Seq
instance TraversableWithIndex Int Seq where
itraversed = traversed
{-# INLINE itraversed #-}
instance FunctorWithIndex Int Vector where
imap = V.imap
{-# INLINE imap #-}
instance FoldableWithIndex Int Vector where
ifoldr = V.ifoldr
{-# INLINE ifoldr #-}
ifoldl = V.ifoldl . flip
{-# INLINE ifoldl #-}
ifoldr' = V.ifoldr'
{-# INLINE ifoldr' #-}
ifoldl' = V.ifoldl' . flip
{-# INLINE ifoldl' #-}
instance TraversableWithIndex Int Vector where
itraversed = traversed
{-# INLINE itraversed #-}
instance FunctorWithIndex Int IntMap
instance FoldableWithIndex Int IntMap
instance TraversableWithIndex Int IntMap where
#if MIN_VERSION_containers(0,5,0)
itraverse = IntMap.traverseWithKey
#else
itraverse f = sequenceA . IntMap.mapWithKey f
#endif
{-# INLINE [0] itraverse #-}
{-# RULES
"itraversed -> mapIntMap" itraversed = sets IntMap.map :: ASetter (IntMap a) (IntMap b) a b;
"itraversed -> imapIntMap" itraversed = isets IntMap.mapWithKey :: AnIndexedSetter Int (IntMap a) (IntMap b) a b;
"itraversed -> foldrIntMap" itraversed = foldring IntMap.foldr :: Getting (Endo r) (IntMap a) a;
"itraversed -> ifoldrIntMap" itraversed = ifoldring IntMap.foldrWithKey :: IndexedGetting Int (Endo r) (IntMap a) a;
#-}
instance FunctorWithIndex k (Map k)
instance FoldableWithIndex k (Map k)
instance TraversableWithIndex k (Map k) where
#if MIN_VERSION_containers(0,5,0)
itraverse = Map.traverseWithKey
#else
itraverse f = sequenceA . Map.mapWithKey f
#endif
{-# INLINE [0] itraverse #-}
{-# RULES
"itraversed -> mapMap" itraversed = sets Map.map :: ASetter (Map k a) (Map k b) a b;
"itraversed -> imapMap" itraversed = isets Map.mapWithKey :: AnIndexedSetter k (Map k a) (Map k b) a b;
"itraversed -> foldrMap" itraversed = foldring Map.foldr :: Getting (Endo r) (Map k a) a;
"itraversed -> ifoldrMap" itraversed = ifoldring Map.foldrWithKey :: IndexedGetting k (Endo r) (Map k a) a;
#-}
instance (Eq k, Hashable k) => FunctorWithIndex k (HashMap k)
instance (Eq k, Hashable k) => FoldableWithIndex k (HashMap k)
instance (Eq k, Hashable k) => TraversableWithIndex k (HashMap k) where
itraverse = HashMap.traverseWithKey
{-# INLINE [0] itraverse #-}
{-# RULES
"itraversed -> mapHashMap" itraversed = sets HashMap.map :: ASetter (HashMap k a) (HashMap k b) a b;
"itraversed -> imapHashMap" itraversed = isets HashMap.mapWithKey :: AnIndexedSetter k (HashMap k a) (HashMap k b) a b;
"itraversed -> foldrHashMap" itraversed = foldring HashMap.foldr :: Getting (Endo r) (HashMap k a) a;
"itraversed -> ifoldrHashMap" itraversed = ifoldring HashMap.foldrWithKey :: IndexedGetting k (Endo r) (HashMap k a) a;
#-}
instance FunctorWithIndex r ((->) r) where
imap f g x = f x (g x)
{-# INLINE imap #-}
instance FunctorWithIndex i (Level i) where
imap f = go where
go (Two n l r) = Two n (go l) (go r)
go (One i a) = One i (f i a)
go Zero = Zero
{-# INLINE imap #-}
instance FoldableWithIndex i (Level i) where
ifoldMap f = go where
go (Two _ l r) = go l `mappend` go r
go (One i a) = f i a
go Zero = mempty
{-# INLINE ifoldMap #-}
instance TraversableWithIndex i (Level i) where
itraverse f = go where
go (Two n l r) = Two n <$> go l <*> go r
go (One i a) = One i <$> f i a
go Zero = pure Zero
{-# INLINE itraverse #-}
instance FunctorWithIndex i (Magma i t b) where
imap f (MagmaAp x y) = MagmaAp (imap f x) (imap f y)
imap _ (MagmaPure x) = MagmaPure x
imap f (MagmaFmap xy x) = MagmaFmap xy (imap f x)
imap f (Magma i a) = Magma i (f i a)
{-# INLINE imap #-}
instance FoldableWithIndex i (Magma i t b) where
ifoldMap f (MagmaAp x y) = ifoldMap f x `mappend` ifoldMap f y
ifoldMap _ MagmaPure{} = mempty
ifoldMap f (MagmaFmap _ x) = ifoldMap f x
ifoldMap f (Magma i a) = f i a
{-# INLINE ifoldMap #-}
instance TraversableWithIndex i (Magma i t b) where
itraverse f (MagmaAp x y) = MagmaAp <$> itraverse f x <*> itraverse f y
itraverse _ (MagmaPure x) = pure (MagmaPure x)
itraverse f (MagmaFmap xy x) = MagmaFmap xy <$> itraverse f x
itraverse f (Magma i a) = Magma i <$> f i a
{-# INLINE itraverse #-}
instance FunctorWithIndex i f => FunctorWithIndex [i] (Free f) where
imap f (Pure a) = Pure $ f [] a
imap f (Free s) = Free $ imap (\i -> imap (f . (:) i)) s
{-# INLINE imap #-}
instance FoldableWithIndex i f => FoldableWithIndex [i] (Free f) where
ifoldMap f (Pure a) = f [] a
ifoldMap f (Free s) = ifoldMap (\i -> ifoldMap (f . (:) i)) s
{-# INLINE ifoldMap #-}
instance TraversableWithIndex i f => TraversableWithIndex [i] (Free f) where
itraverse f (Pure a) = Pure <$> f [] a
itraverse f (Free s) = Free <$> itraverse (\i -> itraverse (f . (:) i)) s
{-# INLINE itraverse #-}
instance Ix i => FunctorWithIndex i (Array i) where
imap f arr = Array.listArray (Array.bounds arr) . fmap (uncurry f) $ Array.assocs arr
{-# INLINE imap #-}
instance Ix i => FoldableWithIndex i (Array i) where
ifoldMap f = foldMap (uncurry f) . Array.assocs
{-# INLINE ifoldMap #-}
instance Ix i => TraversableWithIndex i (Array i) where
itraverse f arr = Array.listArray (Array.bounds arr) <$> traverse (uncurry f) (Array.assocs arr)
{-# INLINE itraverse #-}
instance FunctorWithIndex i f => FunctorWithIndex [i] (Cofree f) where
imap f (a :< as) = f [] a :< imap (\i -> imap (f . (:) i)) as
{-# INLINE imap #-}
instance FoldableWithIndex i f => FoldableWithIndex [i] (Cofree f) where
ifoldMap f (a :< as) = f [] a `mappend` ifoldMap (\i -> ifoldMap (f . (:) i)) as
{-# INLINE ifoldMap #-}
instance TraversableWithIndex i f => TraversableWithIndex [i] (Cofree f) where
itraverse f (a :< as) = (:<) <$> f [] a <*> itraverse (\i -> itraverse (f . (:) i)) as
{-# INLINE itraverse #-}
instance (FunctorWithIndex i f, FunctorWithIndex j g) => FunctorWithIndex (i, j) (Compose f g) where
imap f (Compose fg) = Compose $ imap (\k -> imap (f . (,) k)) fg
{-# INLINE imap #-}
instance (FoldableWithIndex i f, FoldableWithIndex j g) => FoldableWithIndex (i, j) (Compose f g) where
ifoldMap f (Compose fg) = ifoldMap (\k -> ifoldMap (f . (,) k)) fg
{-# INLINE ifoldMap #-}
instance (TraversableWithIndex i f, TraversableWithIndex j g) => TraversableWithIndex (i, j) (Compose f g) where
itraverse f (Compose fg) = Compose <$> itraverse (\k -> itraverse (f . (,) k)) fg
{-# INLINE itraverse #-}
instance FunctorWithIndex i m => FunctorWithIndex i (IdentityT m) where
imap f (IdentityT m) = IdentityT $ imap f m
{-# INLINE imap #-}
instance FoldableWithIndex i m => FoldableWithIndex i (IdentityT m) where
ifoldMap f (IdentityT m) = ifoldMap f m
{-# INLINE ifoldMap #-}
instance TraversableWithIndex i m => TraversableWithIndex i (IdentityT m) where
itraverse f (IdentityT m) = IdentityT <$> itraverse f m
{-# INLINE itraverse #-}
instance (FunctorWithIndex i f, FunctorWithIndex j g) => FunctorWithIndex (Either i j) (Product f g) where
imap f (Pair a b) = Pair (imap (f . Left) a) (imap (f . Right) b)
{-# INLINE imap #-}
instance (FoldableWithIndex i f, FoldableWithIndex j g) => FoldableWithIndex (Either i j) (Product f g) where
ifoldMap f (Pair a b) = ifoldMap (f . Left) a `mappend` ifoldMap (f . Right) b
{-# INLINE ifoldMap #-}
instance (TraversableWithIndex i f, TraversableWithIndex j g) => TraversableWithIndex (Either i j) (Product f g) where
itraverse f (Pair a b) = Pair <$> itraverse (f . Left) a <*> itraverse (f . Right) b
{-# INLINE itraverse #-}
instance FunctorWithIndex i m => FunctorWithIndex (e, i) (ReaderT e m) where
imap f (ReaderT m) = ReaderT $ \k -> imap (f . (,) k) (m k)
{-# INLINE imap #-}
instance FunctorWithIndex i w => FunctorWithIndex (s, i) (TracedT s w) where
imap f (TracedT w) = TracedT $ imap (\k' g k -> f (k, k') (g k)) w
{-# INLINE imap #-}
instance FunctorWithIndex [Int] Tree where
imap f (Node a as) = Node (f [] a) $ imap (\i -> imap (f . (:) i)) as
{-# INLINE imap #-}
instance FoldableWithIndex [Int] Tree where
ifoldMap f (Node a as) = f [] a `mappend` ifoldMap (\i -> ifoldMap (f . (:) i)) as
{-# INLINE ifoldMap #-}
instance TraversableWithIndex [Int] Tree where
itraverse f (Node a as) = Node <$> f [] a <*> itraverse (\i -> itraverse (f . (:) i)) as
{-# INLINE itraverse #-}
skip :: a -> ()
skip _ = ()
{-# INLINE skip #-}
ifoldMapBy :: FoldableWithIndex i t => (r -> r -> r) -> r -> (i -> a -> r) -> t a -> r
ifoldMapBy f z g = reifyFold f z (ifoldMap (\i a -> M (g i a)))
ifoldMapByOf :: (forall s. IndexedGetting i (M r s) t a) -> (r -> r -> r) -> r -> (i -> a -> r) -> t -> r
ifoldMapByOf l f z g = reifyFold f z (ifoldMapOf l (\i a -> M (g i a)))