{-# LANGUAGE CPP #-}
{-# LANGUAGE GADTs #-}
{-# LANGUAGE Rank2Types #-}
{-# LANGUAGE FlexibleContexts #-}
{-# LANGUAGE FlexibleInstances #-}
{-# LANGUAGE MultiParamTypeClasses #-}
{-# LANGUAGE FunctionalDependencies #-}
{-# LANGUAGE ScopedTypeVariables #-}
#ifdef TRUSTWORTHY
{-# LANGUAGE Trustworthy #-}
#endif
#ifndef MIN_VERSION_containers
#define MIN_VERSION_containers(x,y,z) 1
#endif
module Control.Lens.Traversal
(
Traversal, Traversal'
, Traversal1, Traversal1'
, IndexedTraversal, IndexedTraversal'
, IndexedTraversal1, IndexedTraversal1'
, ATraversal, ATraversal'
, ATraversal1, ATraversal1'
, AnIndexedTraversal, AnIndexedTraversal'
, AnIndexedTraversal1, AnIndexedTraversal1'
, Traversing, Traversing'
, Traversing1, Traversing1'
, traverseOf, forOf, sequenceAOf
, mapMOf, forMOf, sequenceOf
, transposeOf
, mapAccumLOf, mapAccumROf
, scanr1Of, scanl1Of
, failover, ifailover
, cloneTraversal
, cloneIndexPreservingTraversal
, cloneIndexedTraversal
, cloneTraversal1
, cloneIndexPreservingTraversal1
, cloneIndexedTraversal1
, partsOf, partsOf'
, unsafePartsOf, unsafePartsOf'
, holesOf
, singular, unsafeSingular
, Traversable(traverse)
, Traversable1(traverse1)
, both
, beside
, taking
, dropping
, failing
, deepOf
, ignored
, TraverseMin(..)
, TraverseMax(..)
, traversed
, traversed1
, traversed64
, elementOf
, element
, elementsOf
, elements
, ipartsOf
, ipartsOf'
, iunsafePartsOf
, iunsafePartsOf'
, itraverseOf
, iforOf
, imapMOf
, iforMOf
, imapAccumROf
, imapAccumLOf
, Bazaar(..), Bazaar'
, Bazaar1(..), Bazaar1'
, loci
, iloci
) where
import Control.Applicative as Applicative
import Control.Applicative.Backwards
import Control.Category
import Control.Comonad
import Control.Lens.Fold
import Control.Lens.Getter (coerced)
import Control.Lens.Internal.Bazaar
import Control.Lens.Internal.Context
import Control.Lens.Internal.Indexed
import Control.Lens.Lens
import Control.Lens.Type
import Control.Monad
import Control.Monad.Trans.State.Lazy
import Data.Bitraversable
import Data.Functor.Compose
import Data.Int
import Data.IntMap as IntMap
import Data.Map as Map
import Data.Monoid
import Data.Profunctor
import Data.Profunctor.Rep
import Data.Profunctor.Unsafe
import Data.Semigroup.Traversable
import Data.Tagged
import Data.Traversable
import Data.Tuple (swap)
import GHC.Magic (inline)
import Prelude hiding ((.),id)
type ATraversal s t a b = LensLike (Bazaar (->) a b) s t a b
type ATraversal' s a = ATraversal s s a a
type ATraversal1 s t a b = LensLike (Bazaar1 (->) a b) s t a b
type ATraversal1' s a = ATraversal1 s s a a
type AnIndexedTraversal i s t a b = Over (Indexed i) (Bazaar (Indexed i) a b) s t a b
type AnIndexedTraversal1 i s t a b = Over (Indexed i) (Bazaar1 (Indexed i) a b) s t a b
type AnIndexedTraversal' i s a = AnIndexedTraversal i s s a a
type AnIndexedTraversal1' i s a = AnIndexedTraversal1 i s s a a
type Traversing p f s t a b = Over p (BazaarT p f a b) s t a b
type Traversing1 p f s t a b = Over p (BazaarT1 p f a b) s t a b
type Traversing' p f s a = Traversing p f s s a a
type Traversing1' p f s a = Traversing1 p f s s a a
traverseOf :: Over p f s t a b -> p a (f b) -> s -> f t
traverseOf = id
{-# INLINE traverseOf #-}
forOf :: Over p f s t a b -> s -> p a (f b) -> f t
forOf = flip
{-# INLINE forOf #-}
sequenceAOf :: LensLike f s t (f b) b -> s -> f t
sequenceAOf l = l id
{-# INLINE sequenceAOf #-}
mapMOf :: Profunctor p => Over p (WrappedMonad m) s t a b -> p a (m b) -> s -> m t
mapMOf l cmd = unwrapMonad #. l (WrapMonad #. cmd)
{-# INLINE mapMOf #-}
forMOf :: Profunctor p => Over p (WrappedMonad m) s t a b -> s -> p a (m b) -> m t
forMOf l a cmd = unwrapMonad (l (WrapMonad #. cmd) a)
{-# INLINE forMOf #-}
sequenceOf :: LensLike (WrappedMonad m) s t (m b) b -> s -> m t
sequenceOf l = unwrapMonad #. l WrapMonad
{-# INLINE sequenceOf #-}
transposeOf :: LensLike ZipList s t [a] a -> s -> [t]
transposeOf l = getZipList #. l ZipList
{-# INLINE transposeOf #-}
mapAccumROf :: Conjoined p => Over p (Backwards (State acc)) s t a b -> p acc (a -> (acc, b)) -> acc -> s -> (acc, t)
mapAccumROf = mapAccumLOf . backwards
{-# INLINE mapAccumROf #-}
mapAccumLOf :: Conjoined p => Over p (State acc) s t a b -> p acc (a -> (acc, b)) -> acc -> s -> (acc, t)
mapAccumLOf l f acc0 s = swap (runState (l g s) acc0) where
g = cotabulate $ \wa -> state $ \acc -> swap (corep f (acc <$ wa) (extract wa))
{-# INLINE mapAccumLOf #-}
scanr1Of :: LensLike (Backwards (State (Maybe a))) s t a a -> (a -> a -> a) -> s -> t
scanr1Of l f = snd . mapAccumROf l step Nothing where
step Nothing a = (Just a, a)
step (Just s) a = (Just r, r) where r = f a s
{-# INLINE scanr1Of #-}
scanl1Of :: LensLike (State (Maybe a)) s t a a -> (a -> a -> a) -> s -> t
scanl1Of l f = snd . mapAccumLOf l step Nothing where
step Nothing a = (Just a, a)
step (Just s) a = (Just r, r) where r = f s a
{-# INLINE scanl1Of #-}
loci :: Traversal (Bazaar (->) a c s) (Bazaar (->) b c s) a b
loci f w = getCompose (runBazaar w (Compose #. fmap sell . f))
{-# INLINE loci #-}
iloci :: IndexedTraversal i (Bazaar (Indexed i) a c s) (Bazaar (Indexed i) b c s) a b
iloci f w = getCompose (runBazaar w (Compose #. Indexed (\i -> fmap (indexed sell i) . indexed f i)))
{-# INLINE iloci #-}
partsOf :: Functor f => Traversing (->) f s t a a -> LensLike f s t [a] [a]
partsOf l f s = outs b <$> f (ins b) where b = l sell s
{-# INLINE partsOf #-}
ipartsOf :: forall i p f s t a. (Indexable [i] p, Functor f) => Traversing (Indexed i) f s t a a -> Over p f s t [a] [a]
ipartsOf l = conjoined
(\f s -> let b = inline l sell s in outs b <$> f (wins b))
(\f s -> let b = inline l sell s; (is, as) = unzip (pins b) in outs b <$> indexed f (is :: [i]) as)
{-# INLINE ipartsOf #-}
partsOf' :: ATraversal s t a a -> Lens s t [a] [a]
partsOf' l f s = outs b <$> f (ins b) where b = l sell s
{-# INLINE partsOf' #-}
ipartsOf' :: forall i p f s t a. (Indexable [i] p, Functor f) => Over (Indexed i) (Bazaar' (Indexed i) a) s t a a -> Over p f s t [a] [a]
ipartsOf' l = conjoined
(\f s -> let b = inline l sell s in outs b <$> f (wins b))
(\f s -> let b = inline l sell s; (is, as) = unzip (pins b) in outs b <$> indexed f (is :: [i]) as)
{-# INLINE ipartsOf' #-}
unsafePartsOf :: Functor f => Traversing (->) f s t a b -> LensLike f s t [a] [b]
unsafePartsOf l f s = unsafeOuts b <$> f (ins b) where b = l sell s
{-# INLINE unsafePartsOf #-}
iunsafePartsOf :: forall i p f s t a b. (Indexable [i] p, Functor f) => Traversing (Indexed i) f s t a b -> Over p f s t [a] [b]
iunsafePartsOf l = conjoined
(\f s -> let b = inline l sell s in unsafeOuts b <$> f (wins b))
(\f s -> let b = inline l sell s; (is,as) = unzip (pins b) in unsafeOuts b <$> indexed f (is :: [i]) as)
{-# INLINE iunsafePartsOf #-}
unsafePartsOf' :: ATraversal s t a b -> Lens s t [a] [b]
unsafePartsOf' l f s = unsafeOuts b <$> f (ins b) where b = l sell s
{-# INLINE unsafePartsOf' #-}
iunsafePartsOf' :: forall i s t a b. Over (Indexed i) (Bazaar (Indexed i) a b) s t a b -> IndexedLens [i] s t [a] [b]
iunsafePartsOf' l = conjoined
(\f s -> let b = inline l sell s in unsafeOuts b <$> f (wins b))
(\f s -> let b = inline l sell s; (is, as) = unzip (pins b) in unsafeOuts b <$> indexed f (is :: [i]) as)
{-# INLINE iunsafePartsOf' #-}
holesOf :: forall p s t a. Conjoined p => Over p (Bazaar p a a) s t a a -> s -> [Pretext p a a t]
holesOf l s = unTagged
( conjoined
(Tagged $ let
f [] _ = []
f (x:xs) g = Pretext (\xfy -> g . (:xs) <$> xfy x) : f xs (g . (x:))
in f (ins b) (unsafeOuts b))
(Tagged $ let
f [] _ = []
f (wx:xs) g = Pretext (\wxfy -> g . (:Prelude.map extract xs) <$> corep wxfy wx) : f xs (g . (extract wx:))
in f (pins b) (unsafeOuts b))
:: Tagged (p a b) [Pretext p a a t]
) where b = l sell s
{-# INLINE holesOf #-}
singular :: (Conjoined p, Functor f)
=> Traversing p f s t a a
-> Over p f s t a a
singular l = conjoined
(\afb s -> let b = l sell s in case ins b of
(w:ws) -> unsafeOuts b . (:ws) <$> afb w
[] -> unsafeOuts b . return <$> afb (error "singular: empty traversal"))
(\pafb s -> let b = l sell s in case pins b of
(w:ws) -> unsafeOuts b . (:Prelude.map extract ws) <$> corep pafb w
[] -> unsafeOuts b . return <$> corep pafb (error "singular: empty traversal"))
{-# INLINE singular #-}
unsafeSingular :: (Conjoined p, Functor f)
=> Traversing p f s t a b
-> Over p f s t a b
unsafeSingular l = conjoined
(\afb s -> let b = inline l sell s in case ins b of
[w] -> unsafeOuts b . return <$> afb w
[] -> error "unsafeSingular: empty traversal"
_ -> error "unsafeSingular: traversing multiple results")
(\pafb s -> let b = inline l sell s in case pins b of
[w] -> unsafeOuts b . return <$> corep pafb w
[] -> error "unsafeSingular: empty traversal"
_ -> error "unsafeSingular: traversing multiple results")
{-# INLINE unsafeSingular #-}
ins :: Bizarre (->) w => w a b t -> [a]
ins = toListOf (coerced bazaar)
{-# INLINE ins #-}
wins :: (Bizarre p w, Corepresentable p, Comonad (Corep p)) => w a b t -> [a]
wins = getConst #. bazaar (cotabulate $ \ra -> Const [extract ra])
{-# INLINE wins #-}
pins :: (Bizarre p w, Corepresentable p) => w a b t -> [Corep p a]
pins = getConst #. bazaar (cotabulate $ \ra -> Const [ra])
{-# INLINE pins #-}
parr :: (Profunctor p, Category p) => (a -> b) -> p a b
parr f = lmap f id
{-# INLINE parr #-}
outs :: (Bizarre p w, Category p) => w a a t -> [a] -> t
outs = evalState `rmap` bazaar (parr (state . unconsWithDefault))
{-# INLINE outs #-}
unsafeOuts :: (Bizarre p w, Corepresentable p) => w a b t -> [b] -> t
unsafeOuts = evalState `rmap` bazaar (cotabulate (\_ -> state (unconsWithDefault fakeVal)))
where fakeVal = error "unsafePartsOf': not enough elements were supplied"
{-# INLINE unsafeOuts #-}
unconsWithDefault :: a -> [a] -> (a,[a])
unconsWithDefault d [] = (d,[])
unconsWithDefault _ (x:xs) = (x,xs)
{-# INLINE unconsWithDefault #-}
both :: Bitraversable r => Traversal (r a a) (r b b) a b
both f = bitraverse f f
{-# INLINE both #-}
beside :: (Representable q, Applicative (Rep q), Applicative f, Bitraversable r)
=> Optical p q f s t a b
-> Optical p q f s' t' a b
-> Optical p q f (r s s') (r t t') a b
beside l r f = tabulate $ getCompose #. bitraverse (Compose #. rep (l f)) (Compose #. rep (r f))
{-# INLINE beside #-}
taking :: (Conjoined p, Applicative f)
=> Int
-> Traversing p f s t a a
-> Over p f s t a a
taking n l = conjoined
(\ afb s -> let b = inline l sell s in outs b <$> traverse afb (take n $ ins b))
(\ pafb s -> let b = inline l sell s in outs b <$> traverse (corep pafb) (take n $ pins b))
{-# INLINE taking #-}
dropping :: (Conjoined p, Applicative f) => Int -> Over p (Indexing f) s t a a -> Over p f s t a a
dropping n l pafb s = snd $ runIndexing (l paifb s) 0 where
paifb = cotabulate $ \wa -> Indexing $ \i -> let i' = i + 1 in i' `seq` (i', if i < n then pure (extract wa) else corep pafb wa)
{-# INLINE dropping #-}
cloneTraversal :: ATraversal s t a b -> Traversal s t a b
cloneTraversal l f = bazaar f . l sell
{-# INLINE cloneTraversal #-}
cloneIndexPreservingTraversal :: ATraversal s t a b -> IndexPreservingTraversal s t a b
cloneIndexPreservingTraversal l pafb = cotabulate $ \ws -> runBazaar (l sell (extract ws)) $ \a -> corep pafb (a <$ ws)
{-# INLINE cloneIndexPreservingTraversal #-}
cloneIndexedTraversal :: AnIndexedTraversal i s t a b -> IndexedTraversal i s t a b
cloneIndexedTraversal l f = bazaar (Indexed (indexed f)) . l sell
{-# INLINE cloneIndexedTraversal #-}
cloneTraversal1 :: ATraversal1 s t a b -> Traversal1 s t a b
cloneTraversal1 l f = bazaar1 f . l sell
{-# INLINE cloneTraversal1 #-}
cloneIndexPreservingTraversal1 :: ATraversal1 s t a b -> IndexPreservingTraversal1 s t a b
cloneIndexPreservingTraversal1 l pafb = cotabulate $ \ws -> runBazaar1 (l sell (extract ws)) $ \a -> corep pafb (a <$ ws)
{-# INLINE cloneIndexPreservingTraversal1 #-}
cloneIndexedTraversal1 :: AnIndexedTraversal1 i s t a b -> IndexedTraversal1 i s t a b
cloneIndexedTraversal1 l f = bazaar1 (Indexed (indexed f)) . l sell
{-# INLINE cloneIndexedTraversal1 #-}
itraverseOf :: (Indexed i a (f b) -> s -> f t) -> (i -> a -> f b) -> s -> f t
itraverseOf l = l .# Indexed
{-# INLINE itraverseOf #-}
iforOf :: (Indexed i a (f b) -> s -> f t) -> s -> (i -> a -> f b) -> f t
iforOf = flip . itraverseOf
{-# INLINE iforOf #-}
imapMOf :: (Indexed i a (WrappedMonad m b) -> s -> WrappedMonad m t) -> (i -> a -> m b) -> s -> m t
imapMOf l = mapMOf l .# Indexed
{-# INLINE imapMOf #-}
iforMOf :: (Indexed i a (WrappedMonad m b) -> s -> WrappedMonad m t) -> s -> (i -> a -> m b) -> m t
iforMOf = flip . imapMOf
{-# INLINE iforMOf #-}
imapAccumROf :: Over (Indexed i) (Backwards (State acc)) s t a b -> (i -> acc -> a -> (acc, b)) -> acc -> s -> (acc, t)
imapAccumROf l = mapAccumROf l .# Indexed
{-# INLINE imapAccumROf #-}
imapAccumLOf :: Over (Indexed i) (State acc) s t a b -> (i -> acc -> a -> (acc, b)) -> acc -> s -> (acc, t)
imapAccumLOf l = mapAccumLOf l .# Indexed
{-# INLINE imapAccumLOf #-}
traversed :: Traversable f => IndexedTraversal Int (f a) (f b) a b
traversed = conjoined traverse (indexing traverse)
{-# INLINE traversed #-}
traversed1 :: Traversable1 f => IndexedTraversal1 Int (f a) (f b) a b
traversed1 = conjoined traverse1 (indexing traverse1)
{-# INLINE traversed1 #-}
traversed64 :: Traversable f => IndexedTraversal Int64 (f a) (f b) a b
traversed64 = conjoined traverse (indexing64 traverse)
{-# INLINE traversed64 #-}
ignored :: Applicative f => pafb -> s -> f s
ignored _ = pure
{-# INLINE ignored #-}
class Ord k => TraverseMin k m | m -> k where
traverseMin :: IndexedTraversal' k (m v) v
instance TraverseMin Int IntMap where
traverseMin f m = case IntMap.minViewWithKey m of
#if MIN_VERSION_containers(0,5,0)
Just ((k,a), _) -> indexed f k a <&> \v -> IntMap.updateMin (const (Just v)) m
#else
Just ((k,a), _) -> indexed f k a <&> \v -> IntMap.updateMin (const v) m
#endif
Nothing -> pure m
{-# INLINE traverseMin #-}
instance Ord k => TraverseMin k (Map k) where
traverseMin f m = case Map.minViewWithKey m of
Just ((k, a), _) -> indexed f k a <&> \v -> Map.updateMin (const (Just v)) m
Nothing -> pure m
{-# INLINE traverseMin #-}
class Ord k => TraverseMax k m | m -> k where
traverseMax :: IndexedTraversal' k (m v) v
instance TraverseMax Int IntMap where
traverseMax f m = case IntMap.maxViewWithKey m of
#if MIN_VERSION_containers(0,5,0)
Just ((k,a), _) -> indexed f k a <&> \v -> IntMap.updateMax (const (Just v)) m
#else
Just ((k,a), _) -> indexed f k a <&> \v -> IntMap.updateMax (const v) m
#endif
Nothing -> pure m
{-# INLINE traverseMax #-}
instance Ord k => TraverseMax k (Map k) where
traverseMax f m = case Map.maxViewWithKey m of
Just ((k, a), _) -> indexed f k a <&> \v -> Map.updateMax (const (Just v)) m
Nothing -> pure m
{-# INLINE traverseMax #-}
elementOf :: Applicative f
=> LensLike (Indexing f) s t a a
-> Int
-> IndexedLensLike Int f s t a a
elementOf l p = elementsOf l (p ==)
{-# INLINE elementOf #-}
element :: Traversable t => Int -> IndexedTraversal' Int (t a) a
element = elementOf traverse
{-# INLINE element #-}
elementsOf :: Applicative f
=> LensLike (Indexing f) s t a a
-> (Int -> Bool)
-> IndexedLensLike Int f s t a a
elementsOf l p iafb s = snd $ runIndexing (l (\a -> Indexing (\i -> i `seq` (i + 1, if p i then indexed iafb i a else pure a))) s) 0
{-# INLINE elementsOf #-}
elements :: Traversable t => (Int -> Bool) -> IndexedTraversal' Int (t a) a
elements = elementsOf traverse
{-# INLINE elements #-}
failover :: (Profunctor p, Alternative m) => Over p ((,) Any) s t a b -> p a b -> s -> m t
failover l pafb s = case l ((,) (Any True) `rmap` pafb) s of
(Any True, t) -> pure t
(Any False, _) -> Applicative.empty
{-# INLINE failover #-}
ifailover :: Alternative m => Over (Indexed i) ((,) Any) s t a b -> (i -> a -> b) -> s -> m t
ifailover l f = failover l (Indexed f)
{-# INLINE ifailover #-}
failing :: (Conjoined p, Applicative f) => Traversing p f s t a b -> Traversing p f s t a b -> Over p f s t a b
failing l r pafb s = case pins b of
[] -> runBazaarT (r sell s) pafb
xs -> unsafeOuts b <$> traverse (corep pafb) xs
where b = l sell s
infixl 5 `failing`
deepOf :: (Conjoined p, Applicative f) => LensLike f s t s t -> Traversing p f s t a b -> Over p f s t a b
deepOf r l pafb = go
where go s = case pins b of
[] -> r go s
xs -> unsafeOuts b <$> traverse (corep pafb) xs
where b = l sell s