diff --git a/CHANGELOG.markdown b/CHANGELOG.markdown
--- a/CHANGELOG.markdown
+++ b/CHANGELOG.markdown
@@ -1,3 +1,10 @@
+4.11.1
+------
+* Added `cosmos`, `cosmosOf`, `cosmosOn`, `cosmosOnOf` to `Control.Lens.Plated`.
+* Added `icontains`, `iat`, `iix`.
+* Made various documentation improvements.
+* Added a `test-templates` flag.
+
 4.11
 ----
 * Proper `profunctors` 5.1 support. This extended the superclass constraints for `Conjoined`, so it resulted in a major version bump.
diff --git a/benchmarks/folds.hs b/benchmarks/folds.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/folds.hs
@@ -0,0 +1,110 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE BangPatterns #-}
+
+import qualified Data.ByteString as BS
+import qualified Data.HashMap.Lazy as HM
+import qualified Data.Map as M
+import qualified Data.Sequence as S
+import qualified Data.Vector as V
+import qualified Data.Vector.Unboxed as U
+
+import Data.Vector.Generic.Lens
+import Data.ByteString.Lens
+
+import Control.Lens
+import Criterion.Main
+import Criterion.Types
+import Data.Foldable
+
+main :: IO ()
+main = defaultMainWith config
+  [
+    bgroup "vector"
+    [ bgroup "toList"
+      [ bench "native" $ nf V.toList v
+      , bench "each"   $ nf (toListOf each) v
+      ]
+    , bgroup "itoList"
+      [ bench "native"     $ nf (V.toList . V.indexed) v
+      , bench "itraversed" $ nf (itoListOf itraversed) v
+      ]
+    ]
+  , bgroup "unboxed-vector"
+    [ bgroup "toList"
+      [ bench "native" $ nf U.toList u
+      , bench "each"   $ nf (toListOf each) u
+      ]
+    , bgroup "itoList"
+      [ bench "native"     $ nf (U.toList . U.indexed) u
+      , bench "vTraverse" $ nf (itoListOf vectorTraverse) u
+      ]
+    ]
+  , bgroup "sequence"
+    [ bgroup "toList"
+      [ bench "native" $ nf toList s
+      , bench "each"   $ nf (toListOf each) s
+      ]
+    , bgroup "itoList"
+      [ bench "native"     $ nf (toList . S.mapWithIndex (,)) s
+      , bench "itraversed" $ nf (itoListOf itraversed) s
+      ]
+    ]
+  , bgroup "bytestring"
+    [ bgroup "toList"
+      [ bench "native" $ nf BS.unpack b
+      , bench "bytes"  $ nf (toListOf bytes) b
+      , bench "each"   $ nf (toListOf each) b
+      ]
+    , bgroup "itoList"
+      [ bench "native" $ nf (zip [(0::Int)..] . BS.unpack) b
+      , bench "bytes"  $ nf (itoListOf bytes) b
+      ]
+    ]
+  , bgroup "list"
+    [ bgroup "toList"
+      [ bench "native" $ nf toList l
+      , bench "each"   $ nf (toListOf each) l
+      ]
+    , bgroup "itoList"
+      [ bench "native"     $ nf (zip [(0::Int)..]) l
+      , bench "itraversed" $ nf (itoListOf itraversed) l
+      ]
+    ]
+  , bgroup "map"
+    [ bgroup "toList"
+      [ bench "native" $ nf toList m
+      , bench "each"   $ nf itoList m
+      ]
+    , bgroup "itoList"
+      [ bench "native"     $ nf (zip [(0::Int)..] . toList) m
+      , bench "itraversed" $ nf (itoListOf itraversed) m
+      ]
+    ]
+  , bgroup "hash map"
+    [ bgroup "toList"
+      [ bench "native" $ nf HM.keys h
+      , bench "each"   $ nf (toListOf each) h
+      ]
+    , bgroup "itoList"
+      [ bench "native"     $ nf HM.toList h
+      , bench "itoList"    $ nf itoList h
+      , bench "itraversed" $ nf (itoListOf itraversed) h
+      ]
+    , bgroup "sum"
+      [ bench "native" $ nf (sum . id . toList) h
+      , bench "each"   $ nf (sumOf each) h
+      ]
+    ]
+  ]
+  where
+    config = defaultConfig { timeLimit = 1 }
+    l = [0..10000] :: [Int]
+    b = BS.pack $ map fromIntegral l
+    h = HM.fromList $ zip l l
+    m = M.fromList $ zip l l
+    s = S.fromList l
+    u = U.fromList l
+    v = V.fromList l
+
diff --git a/benchmarks/traversals.hs b/benchmarks/traversals.hs
new file mode 100644
--- /dev/null
+++ b/benchmarks/traversals.hs
@@ -0,0 +1,104 @@
+{-# LANGUAGE RankNTypes #-}
+{-# LANGUAGE FlexibleContexts #-}
+{-# LANGUAGE DeriveFunctor #-}
+{-# LANGUAGE BangPatterns #-}
+
+import qualified Data.ByteString as BS
+import qualified Data.HashMap.Strict as HM
+import qualified Data.Map as M
+import qualified Data.Sequence as S
+import qualified Data.Vector as V
+import qualified Data.Vector.Unboxed as U
+
+import Data.Vector.Generic.Lens
+import Data.ByteString.Lens
+
+import Control.Lens
+import Criterion.Main
+import Criterion.Types
+
+main :: IO ()
+main = defaultMainWith config
+  [
+    bgroup "vector"
+    [ bgroup "map"
+      [ bench "native"     $ nf (V.map (+100)) v
+      , bench "itraversed" $ nf (over itraversed (+100)) v
+      ]
+    , bgroup "imap"
+      [ bench "native"     $ nf (V.imap           (\i x -> x + i +100)) v
+      , bench "imap"       $ nf (imap             (\i x -> x + i +100)) v
+      , bench "itraversed" $ nf (iover itraversed (\i x -> x + i +100)) v
+      ]
+    ]
+  , bgroup "unboxed-vector"
+    [ bgroup "map"
+      [ bench "native"     $ nf (U.map (+100)) u
+      , bench "itraversed" $ nf (over each (+100)) u
+      ]
+    , bgroup "imap"
+      [ bench "native"     $ nf (U.imap (\i x -> x + i +100)) u
+      , bench "itraversed" $ nf (iover vectorTraverse (\i x -> x + i) :: U.Vector Int -> U.Vector Int) u
+      ]
+    ]
+  , bgroup "sequence"
+    [ bgroup "map"
+      [ bench "native" $ nf (fmap            (+100)) s
+      , bench "each"   $ nf (over each       (+100)) s
+      ]
+    , bgroup "imap"
+      [ bench "native" $ nf (S.mapWithIndex    (\i x -> x + i +100)) s
+      , bench "imap"   $ nf (imap              (\i x -> x + i +100)) s
+      ]
+    ]
+  , bgroup "bytestring"
+    [ bgroup "map"
+      [ bench "native" $ nf (BS.map     (+100)) b
+      , bench "each"   $ nf (over each  (+100)) b
+      ]
+    , bgroup "imap"
+      [
+        bench "bytes" $ nf (iover bytes (\i x -> x + fromIntegral i +100)) b
+      ]
+    ]
+  , bgroup "list"
+    [ bgroup "map"
+      [ bench "native" $ nf (map       (+100)) l
+      , bench "each"   $ nf (over each (+100)) l
+      ]
+    , bgroup "imap"
+      [ bench "imap" $ nf (imap (\i x -> x + i +100)) l
+      ]
+    ]
+  , bgroup "map"
+    [ bgroup "map"
+      [ bench "native"     $ nf (fmap            (+100)) m
+      , bench "each"       $ nf (over each       (+100)) m
+      , bench "itraversed" $ nf (over itraversed (+100)) m
+      ]
+    , bgroup "imap"
+      [ bench "native" $ nf (M.mapWithKey (\i x -> x + i +100)) m
+      , bench "each"   $ nf (imap         (\i x -> x + i +100)) m
+      ]
+    ]
+  , bgroup "hash map"
+    [ bgroup "map"
+      [ bench "native" $ nf (HM.map    (+100)) h
+      , bench "each"   $ nf (over each (+100)) h
+      ]
+    , bgroup "imap"
+      [ bench "native" $ nf (HM.mapWithKey (\i x -> x + i +100)) h
+      , bench "imap"   $ nf (imap          (\i x -> x + i +100)) h
+      ]
+    ]
+  ]
+  where
+    config = defaultConfig { timeLimit = 1 }
+    l  = [0..10000] :: [Int]
+    xl = [0..100000] :: [Int]
+    b  = BS.pack $ map fromIntegral xl
+    h  = HM.fromList $ zip l l
+    m  = M.fromList $ zip l l
+    s  = S.fromList l
+    u  = U.fromList xl
+    v  = V.fromList l
diff --git a/lens.cabal b/lens.cabal
--- a/lens.cabal
+++ b/lens.cabal
@@ -1,6 +1,6 @@
 name:          lens
 category:      Data, Lenses, Generics
-version:       4.11
+version:       4.11.1
 license:       BSD3
 cabal-version: >= 1.8
 license-file:  LICENSE
@@ -160,6 +160,10 @@
   default: True
   manual: True
 
+flag test-templates
+  default: True
+  manual: True
+
 -- Disallow unsafeCoerce
 flag safe
   default: False
@@ -179,6 +183,7 @@
   build-depends:
     array                     >= 0.3.0.2  && < 0.6,
     base                      >= 4.5      && < 5,
+    base-orphans              >= 0.3      && < 1,
     bifunctors                >= 5        && < 6,
     bytestring                >= 0.9.1.10 && < 0.11,
     comonad                   >= 4        && < 5,
@@ -320,13 +325,17 @@
 test-suite templates
   type: exitcode-stdio-1.0
   main-is: templates.hs
-  build-depends: base, lens
-  ghc-options: -Wall -Werror -threaded
+  ghc-options: -Wall -threaded
   hs-source-dirs: tests
 
   if flag(dump-splices)
     ghc-options: -ddump-splices
 
+  if !flag(test-templates)
+    buildable: False
+  else
+    build-depends: base, lens
+
 -- Verify the properties of lenses with QuickCheck
 test-suite properties
   type: exitcode-stdio-1.0
@@ -396,9 +405,6 @@
       unordered-containers,
       vector
 
-  if impl(ghc<7.6.1)
-    ghc-options: -Werror
-
 test-suite hlint
   type: exitcode-stdio-1.0
   main-is: hlint.hs
@@ -446,6 +452,36 @@
     lens,
     transformers
 
+-- Benchmarking folds
+benchmark folds
+  type:           exitcode-stdio-1.0
+  main-is:        folds.hs
+  ghc-options:    -w -O2 -threaded -fdicts-cheap -funbox-strict-fields
+  hs-source-dirs: benchmarks
+  build-depends:
+    base,
+    criterion,
+    containers,
+    bytestring,
+    unordered-containers,
+    vector,
+    lens
+
+-- Benchmarking traversals
+benchmark traversals
+  type:           exitcode-stdio-1.0
+  main-is:        traversals.hs
+  ghc-options:    -w -O2 -threaded -fdicts-cheap -funbox-strict-fields
+  hs-source-dirs: benchmarks
+  build-depends:
+    base,
+    criterion,
+    containers,
+    bytestring,
+    unordered-containers,
+    vector,
+    lens
+
 -- Benchmarking unsafe implementation strategies
 benchmark unsafe
   type:           exitcode-stdio-1.0
@@ -461,7 +497,6 @@
     generic-deriving,
     lens,
     transformers
-
 
 -- Benchmarking zipper usage
 benchmark zipper
diff --git a/lens.sig b/lens.sig
new file mode 100644
Binary files /dev/null and b/lens.sig differ
diff --git a/src/Control/Lens/At.hs b/src/Control/Lens/At.hs
--- a/src/Control/Lens/At.hs
+++ b/src/Control/Lens/At.hs
@@ -30,20 +30,25 @@
 module Control.Lens.At
   (
   -- * At
-    At(at), sans
+    At(at)
+    , sans
+    , iat
   -- * Ixed
   , Index
   , IxValue
   , Ixed(ix)
   , ixAt
+  , iix
   -- * Contains
-  , Contains(..)
+  , Contains(contains)
+  , icontains
   ) where
 
 import Control.Lens.Each
 import Control.Lens.Traversal
 import Control.Lens.Lens
 import Control.Lens.Setter
+import Control.Lens.Indexed
 import Data.Array.IArray as Array
 import Data.Array.Unboxed
 import Data.ByteString as StrictB
@@ -65,7 +70,7 @@
 import Data.Vector as Vector hiding (indexed)
 import Data.Vector.Primitive as Prim
 import Data.Vector.Storable as Storable
-import Data.Vector.Unboxed as Unboxed
+import Data.Vector.Unboxed as Unboxed hiding (indexed)
 import Data.Word
 
 #if !MIN_VERSION_base(4,8,0)
@@ -111,11 +116,13 @@
 -- >>> import Control.Lens
 -- >>> import Debug.SimpleReflect.Expr
 -- >>> import Debug.SimpleReflect.Vars as Vars hiding (f,g)
--- >>> let f :: Expr -> Expr; f = Debug.SimpleReflect.Vars.f
--- >>> let g :: Expr -> Expr; g = Debug.SimpleReflect.Vars.g
+-- >>> let f  :: Expr -> Expr; f = Debug.SimpleReflect.Vars.f
+-- >>> let g  :: Expr -> Expr; g = Debug.SimpleReflect.Vars.g
+-- >>> let f' :: Int -> Expr -> Expr; f' = Debug.SimpleReflect.Vars.f'
+-- >>> let h  :: Int -> Expr; h = Debug.SimpleReflect.Vars.h
 
 -- |
--- This class provides a simple 'IndexedFold' (or 'IndexedTraversal') that lets you view (and modify)
+-- This class provides a simple 'Lens' that lets you view (and modify)
 -- information about whether or not a container contains a given 'Index'.
 class Contains m where
   -- |
@@ -129,6 +136,23 @@
   -- fromList [1,2,4]
   contains :: Index m -> Lens' m Bool
 
+-- | An indexed version of 'contains'.
+--
+-- >>> IntSet.fromList [1,2,3,4] ^@. icontains 3
+-- (3,True)
+--
+-- >>> IntSet.fromList [1,2,3,4] ^@. icontains 5
+-- (5,False)
+--
+-- >>> IntSet.fromList [1,2,3,4] & icontains 3 %@~ \i x -> if odd i then not x else x
+-- fromList [1,2,4]
+--
+-- >>> IntSet.fromList [1,2,3,4] & icontains 3 %@~ \i x -> if even i then not x else x
+-- fromList [1,2,3,4]
+icontains :: Contains m => Index m -> IndexedLens' (Index m) m Bool
+icontains i f = contains i (indexed f i)
+{-# INLINE icontains #-}
+
 instance Contains IntSet where
   contains k f s = f (IntSet.member k s) <&> \b ->
     if b then IntSet.insert k s else IntSet.delete k s
@@ -176,6 +200,23 @@
   {-# INLINE ix #-}
 #endif
 
+-- | An indexed version of 'ix'.
+--
+-- >>> Seq.fromList [a,b,c,d] & iix 2 %@~ f'
+-- fromList [a,b,f' 2 c,d]
+--
+-- >>> Seq.fromList [a,b,c,d] & iix 2 .@~ h
+-- fromList [a,b,h 2,d]
+--
+-- >>> Seq.fromList [a,b,c,d] ^@? iix 2
+-- Just (2,c)
+--
+-- >>> Seq.fromList [] ^@? iix 2
+-- Nothing
+iix :: Ixed m => Index m -> IndexedTraversal' (Index m) m (IxValue m)
+iix i f = ix i (indexed f i)
+{-# INLINE iix #-}
+
 -- | A definition of 'ix' for types with an 'At' instance. This is the default
 -- if you don't specify a definition for 'ix'.
 ixAt :: At m => Index m -> Traversal' m (IxValue m)
@@ -389,6 +430,21 @@
 sans :: At m => Index m -> m -> m
 sans k m = m & at k .~ Nothing
 {-# INLINE sans #-}
+
+-- | An indexed version of 'at'.
+--
+-- >>> Map.fromList [(1,"world")] ^@. iat 1
+-- (1,Just "world")
+--
+-- >>> iat 1 %@~ (\i x -> if odd i then Just "hello" else Nothing) $ Map.empty
+-- fromList [(1,"hello")]
+--
+-- >>> iat 2 %@~ (\i x -> if odd i then Just "hello" else Nothing) $ Map.empty
+-- fromList []
+--
+iat :: At m => Index m -> IndexedLens' (Index m) m (Maybe (IxValue m))
+iat i f = at i (indexed f i)
+{-# INLINE iat #-}
 
 instance At (Maybe a) where
   at () f = f
diff --git a/src/Control/Lens/Each.hs b/src/Control/Lens/Each.hs
--- a/src/Control/Lens/Each.hs
+++ b/src/Control/Lens/Each.hs
@@ -30,8 +30,8 @@
     Each(..)
   ) where
 
-import Control.Lens.Iso
 import Control.Lens.Traversal
+import Control.Lens.Internal.ByteString
 import Data.Array.Unboxed as Unboxed
 import Data.Array.IArray as IArray
 import Data.ByteString as StrictB
@@ -43,9 +43,11 @@
 import Data.List.NonEmpty
 import Data.Map as Map
 import Data.Sequence as Seq
+import Data.Text.Lens (text)
 import Data.Text as StrictT
 import Data.Text.Lazy as LazyT
 import Data.Tree as Tree
+import Data.Vector.Generic.Lens (vectorTraverse)
 import qualified Data.Vector as Vector
 import qualified Data.Vector.Primitive as Prim
 import Data.Vector.Primitive (Prim)
@@ -133,16 +135,24 @@
   {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' ('Map' c a) ('Map' c b) a b@
-instance (c ~ d) => Each (Map c a) (Map d b) a b
+instance (c ~ d) => Each (Map c a) (Map d b) a b where
+  each = traversed
+  {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' ('Map' c a) ('Map' c b) a b@
-instance Each (IntMap a) (IntMap b) a b
+instance Each (IntMap a) (IntMap b) a b where
+  each = traversed
+  {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' ('HashMap' c a) ('HashMap' c b) a b@
-instance (c ~ d) => Each (HashMap c a) (HashMap d b) a b
+instance (c ~ d) => Each (HashMap c a) (HashMap d b) a b where
+  each = traversed
+  {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' [a] [b] a b@
-instance Each [a] [b] a b
+instance Each [a] [b] a b where
+  each = traversed
+  {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' (NonEmpty a) (NonEmpty b) a b@
 instance Each (NonEmpty a) (NonEmpty b) a b
@@ -154,47 +164,51 @@
 instance Each (Maybe a) (Maybe b) a b
 
 -- | @'each' :: 'Traversal' ('Seq' a) ('Seq' b) a b@
-instance Each (Seq a) (Seq b) a b
+instance Each (Seq a) (Seq b) a b where
+  each = traversed
+  {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' ('Tree' a) ('Tree' b) a b@
 instance Each (Tree a) (Tree b) a b
 
 -- | @'each' :: 'Traversal' ('Vector.Vector' a) ('Vector.Vector' b) a b@
-instance Each (Vector.Vector a) (Vector.Vector b) a b
+instance Each (Vector.Vector a) (Vector.Vector b) a b where
+  each = vectorTraverse
+  {-# INLINE each #-}
 
 -- | @'each' :: ('Prim' a, 'Prim' b) => 'Traversal' ('Prim.Vector' a) ('Prim.Vector' b) a b@
 instance (Prim a, Prim b) => Each (Prim.Vector a) (Prim.Vector b) a b where
-  each f v = Prim.fromListN (Prim.length v) <$> traverse f (Prim.toList v)
+  each = vectorTraverse
   {-# INLINE each #-}
 
 -- | @'each' :: ('Storable' a, 'Storable' b) => 'Traversal' ('Storable.Vector' a) ('Storable.Vector' b) a b@
 instance (Storable a, Storable b) => Each (Storable.Vector a) (Storable.Vector b) a b where
-  each f v = Storable.fromListN (Storable.length v) <$> traverse f (Storable.toList v)
+  each = vectorTraverse
   {-# INLINE each #-}
 
 -- | @'each' :: ('Unbox' a, 'Unbox' b) => 'Traversal' ('Unboxed.Vector' a) ('Unboxed.Vector' b) a b@
 instance (Unbox a, Unbox b) => Each (Unboxed.Vector a) (Unboxed.Vector b) a b where
-  each f v = Unboxed.fromListN (Unboxed.length v) <$> traverse f (Unboxed.toList v)
+  each = vectorTraverse
   {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' 'StrictT.Text' 'StrictT.Text' 'Char' 'Char'@
 instance (a ~ Char, b ~ Char) => Each StrictT.Text StrictT.Text a b where
-  each = iso StrictT.unpack StrictT.pack . traversed
+  each = text
   {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' 'LazyT.Text' 'LazyT.Text' 'Char' 'Char'@
 instance (a ~ Char, b ~ Char) => Each LazyT.Text LazyT.Text a b where
-  each = iso LazyT.unpack LazyT.pack . traverse
+  each = text
   {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' 'StrictB.ByteString' 'StrictB.ByteString' 'Word8' 'Word8'@
 instance (a ~ Word8, b ~ Word8) => Each StrictB.ByteString StrictB.ByteString a b where
-  each = iso StrictB.unpack StrictB.pack . traverse
+  each = traversedStrictTree
   {-# INLINE each #-}
 
 -- | @'each' :: 'Traversal' 'LazyB.ByteString' 'LazyB.ByteString' 'Word8' 'Word8'@
 instance (a ~ Word8, b ~ Word8) => Each LazyB.ByteString LazyB.ByteString a b where
-  each = iso LazyB.unpack LazyB.pack . traverse
+  each = traversedLazy
   {-# INLINE each #-}
 
 -- | @'each' :: 'Ix' i => 'Traversal' ('Array' i a) ('Array' i b) a b@
diff --git a/src/Control/Lens/Fold.hs b/src/Control/Lens/Fold.hs
--- a/src/Control/Lens/Fold.hs
+++ b/src/Control/Lens/Fold.hs
@@ -52,6 +52,7 @@
 
   -- ** Building Folds
   , folding, ifolding
+  , foldring, ifoldring
   , folded
   , folded64
   , unfolded
@@ -148,7 +149,7 @@
 import Control.Monad as Monad
 import Control.Monad.Reader
 import Control.Monad.State
-import Data.Foldable as Foldable
+import Data.Foldable
 import Data.Functor.Apply
 import Data.Functor.Compose
 import Data.Int (Int64)
@@ -160,7 +161,7 @@
 import Data.Profunctor.Sieve
 import Data.Profunctor.Unsafe
 import Data.Traversable
-import Prelude
+import Prelude hiding (foldr)
 
 -- $setup
 -- >>> :set -XNoOverloadedStrings
@@ -204,6 +205,19 @@
 ifolding sfa f = coerce . traverse_ (coerce . uncurry (indexed f)) . sfa
 {-# INLINE ifolding #-}
 
+-- | Obtain a 'Fold' by lifting 'foldr' like function.
+--
+-- >>> [1,2,3,4]^..foldring foldr
+-- [1,2,3,4]
+foldring :: (Contravariant f, Applicative f) => ((a -> f a -> f a) -> f a -> s -> f a) -> LensLike f s t a b
+foldring fr f = coerce . fr (\a fa -> f a *> fa) noEffect
+{-# INLINE foldring #-}
+
+-- | Obtain 'FoldWithIndex' by lifting 'ifoldr' like function.
+ifoldring :: (Indexable i p, Contravariant f, Applicative f) => ((i -> a -> f a -> f a) -> f a -> s -> f a) -> Over p f s t a b
+ifoldring ifr f = coerce . ifr (\i a fa -> indexed f i a *> fa) noEffect
+{-# INLINE ifoldring #-}
+
 -- | Obtain a 'Fold' from any 'Foldable' indexed by ordinal position.
 --
 -- >>> Just 3^..folded
@@ -215,17 +229,21 @@
 -- >>> [(1,2),(3,4)]^..folded.both
 -- [1,2,3,4]
 folded :: Foldable f => IndexedFold Int (f a) a
-folded = conjoined folded' (indexing folded')
+folded = conjoined (foldring foldr) (ifoldring ifoldr)
 {-# INLINE folded #-}
 
+ifoldr :: Foldable f => (Int -> a -> b -> b) -> b -> f a -> b
+ifoldr f z xs = foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldr #-}
+
 -- | Obtain a 'Fold' from any 'Foldable' indexed by ordinal position.
 folded64 :: Foldable f => IndexedFold Int64 (f a) a
-folded64 = conjoined folded' (indexing64 folded')
+folded64 = conjoined (foldring foldr) (ifoldring ifoldr64)
 {-# INLINE folded64 #-}
 
-folded' :: Foldable f => Fold (f a) a
-folded' f = coerce . getFolding . foldMap (Folding #. f)
-{-# INLINE folded' #-}
+ifoldr64 :: Foldable f => (Int64 -> a -> b -> b) -> b -> f a -> b
+ifoldr64 f z xs = foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldr64 #-}
 
 -- | Form a 'Fold1' by repeating the input forever.
 --
@@ -2292,7 +2310,7 @@
 -- When you don't need access to the indices in the result, then 'toListOf' is more flexible in what it accepts.
 --
 -- @
--- 'toListOf' l ≡ 'map' 'fst' '.' 'itoListOf' l
+-- 'toListOf' l ≡ 'map' 'snd' '.' 'itoListOf' l
 -- @
 --
 -- @
diff --git a/src/Control/Lens/Indexed.hs b/src/Control/Lens/Indexed.hs
--- a/src/Control/Lens/Indexed.hs
+++ b/src/Control/Lens/Indexed.hs
@@ -107,7 +107,9 @@
 import Data.Monoid hiding (Product)
 import Data.Profunctor.Unsafe
 import Data.Sequence hiding ((:<), index)
-import Data.Traversable
+#if !(MIN_VERSION_containers(0,5,0))
+import Data.Traversable (sequenceA)
+#endif
 import Data.Tree
 import Data.Tuple (swap)
 import Data.Vector (Vector)
@@ -609,8 +611,8 @@
 instance FunctorWithIndex Int []
 instance FoldableWithIndex Int []
 instance TraversableWithIndex Int [] where
-  itraverse = itraverseOf traversed
-  {-# INLINE itraverse #-}
+  itraversed = traversed
+  {-# INLINE itraversed #-}
 
 instance FunctorWithIndex Int NonEmpty
 instance FoldableWithIndex Int NonEmpty
@@ -632,8 +634,8 @@
 instance FunctorWithIndex Int Seq
 instance FoldableWithIndex Int Seq
 instance TraversableWithIndex Int Seq where
-  itraverse = itraverseOf traversed
-  {-# INLINE itraverse #-}
+  itraversed = traversed
+  {-# INLINE itraversed #-}
 
 instance FunctorWithIndex Int Vector where
   imap = V.imap
@@ -648,8 +650,8 @@
   ifoldl' = V.ifoldl' . flip
   {-# INLINE ifoldl' #-}
 instance TraversableWithIndex Int Vector where
-  itraverse f = sequenceA . V.imap f
-  {-# INLINE itraverse #-}
+  itraversed = traversed
+  {-# INLINE itraversed #-}
 
 instance FunctorWithIndex Int IntMap
 instance FoldableWithIndex Int IntMap
@@ -659,8 +661,15 @@
 #else
   itraverse f = sequenceA . IntMap.mapWithKey f
 #endif
-  {-# INLINE itraverse #-}
+  {-# 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
@@ -669,13 +678,27 @@
 #else
   itraverse f = sequenceA . Map.mapWithKey f
 #endif
-  {-# INLINE itraverse #-}
+  {-# 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 itraverse #-}
+  {-# 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)
diff --git a/src/Control/Lens/Internal/ByteString.hs b/src/Control/Lens/Internal/ByteString.hs
--- a/src/Control/Lens/Internal/ByteString.hs
+++ b/src/Control/Lens/Internal/ByteString.hs
@@ -39,11 +39,13 @@
 import Control.Applicative
 #endif
 
-import Control.Lens
+import Control.Lens.Type
+import Control.Lens.Getter
+import Control.Lens.Fold
+import Control.Lens.Indexed
+import Control.Lens.Setter
 import qualified Data.ByteString               as B
-#if MIN_VERSION_bytestring(0,10,4)
 import qualified Data.ByteString.Char8         as B8
-#endif
 import qualified Data.ByteString.Lazy          as BL
 import qualified Data.ByteString.Lazy.Char8    as BL8
 import qualified Data.ByteString.Internal      as BI
@@ -52,6 +54,7 @@
 import Data.Char
 import Data.Int (Int64)
 import Data.Word (Word8)
+import Data.Monoid
 import Foreign.Ptr
 import Foreign.Storable
 #if MIN_VERSION_base(4,8,0)
@@ -85,9 +88,23 @@
      | i == j    = pure (\_ -> return ())
      | otherwise = let !x = BU.unsafeIndex bs i
                    in (\y ys q -> pokeByteOff q i y >> ys q) <$> indexed pafb (i :: Int) x <*> run (i + 1) j
-{-# INLINE traversedStrictTree #-}
+{-# INLINE [0] traversedStrictTree #-}
 
+{-# RULES
+"bytes -> map"    traversedStrictTree = sets B.map        :: ASetter' B.ByteString Word8;
+"bytes -> imap"   traversedStrictTree = isets imapB       :: AnIndexedSetter' Int B.ByteString Word8;
+"bytes -> foldr"  traversedStrictTree = foldring B.foldr  :: Getting (Endo r) B.ByteString Word8;
+"bytes -> ifoldr" traversedStrictTree = ifoldring ifoldrB :: IndexedGetting Int (Endo r) B.ByteString Word8;
+ #-}
 
+imapB :: (Int -> Word8 -> Word8) -> B.ByteString -> B.ByteString
+imapB f = snd . B.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
+{-# INLINE imapB #-}
+
+ifoldrB :: (Int -> Word8 -> a -> a) -> a -> B.ByteString -> a
+ifoldrB f z xs = B.foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldrB #-}
+
 -- | Traverse a strict 'B.ByteString' in a relatively balanced fashion, as a balanced tree with biased runs of
 -- elements at the leaves, pretending the bytes are chars.
 traversedStrictTree8 :: IndexedTraversal' Int B.ByteString Char
@@ -104,8 +121,23 @@
                           in (\y ys q -> pokeByteOff q i (c2w y) >> ys q)
                          <$> indexed pafb (i :: Int) (w2c x)
                          <*> run (i + 1) j
-{-# INLINE traversedStrictTree8 #-}
+{-# INLINE [0] traversedStrictTree8 #-}
 
+{-# RULES
+"chars -> map"    traversedStrictTree8 = sets B8.map        :: ASetter' B.ByteString Char;
+"chars -> imap"   traversedStrictTree8 = isets imapB8       :: AnIndexedSetter' Int B.ByteString Char;
+"chars -> foldr"  traversedStrictTree8 = foldring B8.foldr  :: Getting (Endo r) B.ByteString Char;
+"chars -> ifoldr" traversedStrictTree8 = ifoldring ifoldrB8 :: IndexedGetting Int (Endo r) B.ByteString Char;
+ #-}
+
+imapB8 :: (Int -> Char -> Char) -> B.ByteString -> B.ByteString
+imapB8 f = snd . B8.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
+{-# INLINE imapB8 #-}
+
+ifoldrB8 :: (Int -> Char -> a -> a) -> a -> B.ByteString -> a
+ifoldrB8 f z xs = B8.foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldrB8 #-}
+
 -- | Unpack a lazy 'Bytestring'
 unpackLazy :: BL.ByteString -> [Word8]
 unpackLazy = BL.unpack
@@ -121,9 +153,27 @@
     where
     acc' :: Int64
     !acc' = acc + fromIntegral (B.length c)
-{-# INLINE traversedLazy #-}
+{-# INLINE [1] traversedLazy #-}
 
+{-# RULES
+  "sets lazy bytestring"
+    traversedLazy = sets BL.map :: ASetter' BL.ByteString Word8;
+  "isets lazy bytestring"
+    traversedLazy = isets imapBL :: AnIndexedSetter' Int BL.ByteString Word8;
+  "gets lazy bytestring"
+    traversedLazy = foldring BL.foldr :: Getting (Endo r) BL.ByteString Word8;
+  "igets lazy bytestring"
+    traversedLazy = ifoldring ifoldrBL :: IndexedGetting Int (Endo r) BL.ByteString Word8;
+ #-}
 
+imapBL :: (Int -> Word8 -> Word8) -> BL.ByteString -> BL.ByteString
+imapBL f = snd . BL.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
+{-# INLINE imapBL #-}
+
+ifoldrBL :: (Int -> Word8 -> a -> a) -> a -> BL.ByteString -> a
+ifoldrBL f z xs = BL.foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldrBL #-}
+
 -- | Unpack a lazy 'BL.ByteString' pretending the bytes are chars.
 unpackLazy8 :: BL.ByteString -> String
 unpackLazy8 = BL8.unpack
@@ -139,7 +189,26 @@
     where
     acc' :: Int64
     !acc' = acc + fromIntegral (B.length c)
-{-# INLINE traversedLazy8 #-}
+{-# INLINE [1] traversedLazy8 #-}
+
+{-# RULES
+  "sets lazy bytestring"
+    traversedLazy8 = sets BL8.map :: ASetter' BL8.ByteString Char;
+  "isets lazy bytestring"
+    traversedLazy8 = isets imapBL8 :: AnIndexedSetter' Int BL8.ByteString Char;
+  "gets lazy bytestring"
+    traversedLazy8 = foldring BL8.foldr :: Getting (Endo r) BL8.ByteString Char;
+  "igets lazy bytestring"
+    traversedLazy8 = ifoldring ifoldrBL8 :: IndexedGetting Int (Endo r) BL8.ByteString Char;
+ #-}
+
+imapBL8 :: (Int -> Char -> Char) -> BL8.ByteString -> BL8.ByteString
+imapBL8 f = snd . BL8.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
+{-# INLINE imapBL8 #-}
+
+ifoldrBL8 :: (Int -> Char -> a -> a) -> a -> BL8.ByteString -> a
+ifoldrBL8 f z xs = BL8.foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldrBL8 #-}
 
 ------------------------------------------------------------------------------
 -- ByteString guts
diff --git a/src/Control/Lens/Internal/Instances.hs b/src/Control/Lens/Internal/Instances.hs
--- a/src/Control/Lens/Internal/Instances.hs
+++ b/src/Control/Lens/Internal/Instances.hs
@@ -1,10 +1,6 @@
 {-# LANGUAGE CPP #-}
 {-# OPTIONS_GHC -fno-warn-orphans #-}
 
-#ifndef MIN_VERSION_base
-#define MIN_VERSION_base(x,y,z) 1
-#endif
-
 #ifndef MIN_VERSION_semigroupoids
 #define MIN_VERSION_semigroupoids(x,y,z) 1
 #endif
@@ -22,6 +18,7 @@
 ----------------------------------------------------------------------------
 module Control.Lens.Internal.Instances () where
 
+import Data.Orphans ()
 import Data.Traversable.Instances ()
 
 #if !(MIN_VERSION_semigroupoids(4,2,0))
@@ -30,38 +27,9 @@
 import Data.Semigroup.Foldable
 import Data.Semigroup.Traversable
 
-
-#if !(MIN_VERSION_base(4,7,0))
-import Data.Monoid
-import Data.Foldable
-import Data.Traversable
-#endif
-
 -------------------------------------------------------------------------------
 -- Orphan Instances
 -------------------------------------------------------------------------------
-
-#if !(MIN_VERSION_base(4,7,0))
-instance Foldable ((,) b) where
-  foldMap f (_, a) = f a
-
-instance Traversable ((,) b) where
-  traverse f (b, a) = (,) b <$> f a
-
-instance Foldable (Either a) where
-  foldMap _ (Left _) = mempty
-  foldMap f (Right a) = f a
-
-instance Traversable (Either a) where
-  traverse _ (Left b) = pure (Left b)
-  traverse f (Right a) = Right <$> f a
-
-instance Foldable (Const m) where
-  foldMap _ _ = mempty
-
-instance Traversable (Const m) where
-  traverse _ (Const m) = pure $ Const m
-#endif
 
 instance Foldable1 ((,) b) where
   foldMap1 f (_, a) = f a
diff --git a/src/Control/Lens/Lens.hs b/src/Control/Lens/Lens.hs
--- a/src/Control/Lens/Lens.hs
+++ b/src/Control/Lens/Lens.hs
@@ -150,6 +150,7 @@
 -- >>> :set -XNoOverloadedStrings
 -- >>> import Control.Lens
 -- >>> import Control.Monad.State
+-- >>> import Data.Char (chr)
 -- >>> import Debug.SimpleReflect.Expr
 -- >>> import Debug.SimpleReflect.Vars as Vars hiding (f,g,h)
 -- >>> let f :: Expr -> Expr; f = Debug.SimpleReflect.Vars.f
@@ -254,6 +255,9 @@
 -- targets of the traversals, extracting an applicative summary of its
 -- actions.
 --
+-- >>> [66,97,116,109,97,110] & each %%~ \a -> ("na", chr a)
+-- ("nananananana","Batman")
+--
 -- For all that the definition of this combinator is just:
 --
 -- @
@@ -355,8 +359,20 @@
 as <&> f = f <$> as
 {-# INLINE (<&>) #-}
 
--- | This is convenient to 'flip' argument order of composite functions.
+-- | This is convenient to 'flip' argument order of composite functions defined as:
 --
+-- @
+-- fab ?? a = fmap ($ a) fab
+-- @
+-- 
+-- For the 'Functor' instance @f = ((->) r)@ you can reason about this function as if the definition was @('??') ≡ 'flip'@:
+-- 
+-- >>> (h ?? x) a
+-- h a x
+-- 
+-- >>> execState ?? [] $ modify (1:)
+-- [1]
+-- 
 -- >>> over _2 ?? ("hello","world") $ length
 -- ("hello",5)
 --
diff --git a/src/Control/Lens/Plated.hs b/src/Control/Lens/Plated.hs
--- a/src/Control/Lens/Plated.hs
+++ b/src/Control/Lens/Plated.hs
@@ -75,6 +75,7 @@
   , rewrite, rewriteOf, rewriteOn, rewriteOnOf
   , rewriteM, rewriteMOf, rewriteMOn, rewriteMOnOf
   , universe, universeOf, universeOn, universeOnOf
+  , cosmos, cosmosOf, cosmosOn, cosmosOnOf
   , transform, transformOf, transformOn, transformOnOf
   , transformM, transformMOf, transformMOn, transformMOnOf
   , contexts, contextsOf, contextsOn, contextsOnOf
@@ -420,6 +421,39 @@
 universeOnOf :: Getting [a] s a -> Getting [a] a a -> s -> [a]
 universeOnOf b = foldMapOf b . universeOf
 {-# INLINE universeOnOf #-}
+
+-- | Fold over all transitive descendants of a 'Plated' container, including itself.
+cosmos :: Plated a => Fold a a
+cosmos = cosmosOf plate
+{-# INLINE cosmos #-}
+
+-- | Given a 'Fold' that knows how to locate immediate children, fold all of the transitive descendants of a node, including itself.
+--
+-- @
+-- 'cosmosOf' :: 'Fold' a a -> 'Fold' a a
+-- @
+cosmosOf :: (Applicative f, Contravariant f) => LensLike' f a a -> LensLike' f a a
+cosmosOf d f s = f s *> d (cosmosOf d f) s
+{-# INLINE cosmosOf #-}
+
+-- | Given a 'Fold' that knows how to find 'Plated' parts of a container fold them and all of their descendants, recursively.
+--
+-- @
+-- 'cosmosOn' :: 'Plated' a => 'Fold' s a -> 'Fold' s a
+-- @
+cosmosOn :: (Applicative f, Contravariant f, Plated a) => LensLike' f a a -> LensLike' f a a
+cosmosOn d = cosmosOnOf d plate
+{-# INLINE cosmosOn #-}
+
+-- | Given a 'Fold' that knows how to locate immediate children, fold all of the transitive descendants of a node, including itself that lie
+-- in a region indicated by another 'Fold'.
+--
+-- @
+-- 'cosmosOnOf' :: 'Fold' s a -> 'Fold' a a -> 'Fold' s a
+-- @
+cosmosOnOf :: (Applicative f, Contravariant f) => LensLike' f s a -> LensLike' f a a -> LensLike' f s a
+cosmosOnOf d p = d . cosmosOf p
+{-# INLINE cosmosOnOf #-}
 
 -------------------------------------------------------------------------------
 -- Transformation
diff --git a/src/Control/Lens/Setter.hs b/src/Control/Lens/Setter.hs
--- a/src/Control/Lens/Setter.hs
+++ b/src/Control/Lens/Setter.hs
@@ -495,7 +495,7 @@
 
 -- | Set with pass-through.
 --
--- This is mostly present for consistency, but may be useful for for chaining assignments.
+-- This is mostly present for consistency, but may be useful for chaining assignments.
 --
 -- If you do not need a copy of the intermediate result, then using @l '.~' t@ directly is a good idea.
 --
diff --git a/src/Control/Lens/Traversal.hs b/src/Control/Lens/Traversal.hs
--- a/src/Control/Lens/Traversal.hs
+++ b/src/Control/Lens/Traversal.hs
@@ -127,21 +127,27 @@
 import Control.Category
 import Control.Comonad
 import Control.Lens.Fold
-import Control.Lens.Getter (coerced)
+import Control.Lens.Getter (Getting, IndexedGetting, coerced)
 import Control.Lens.Internal.Bazaar
 import Control.Lens.Internal.Context
 import Control.Lens.Internal.Indexed
 import Control.Lens.Lens
+import Control.Lens.Setter (ASetter, AnIndexedSetter, isets, sets)
 import Control.Lens.Type
 import Control.Monad
 import Control.Monad.Trans.State.Lazy
 import Data.Bitraversable
+#if __GLASGOW_HASKELL__ < 710
+import Data.Foldable (Foldable)
+#endif
 import Data.Functor.Compose
 import Data.Functor.Kan.Rift
 import Data.Functor.Yoneda
 import Data.Int
 import Data.IntMap as IntMap
 import Data.Map as Map
+import Data.Sequence (Seq, mapWithIndex)
+import Data.Vector as Vector (Vector, imap)
 import Data.Monoid
 import Data.Profunctor
 import Data.Profunctor.Rep
@@ -162,6 +168,7 @@
 -- >>> import Data.Maybe (fromMaybe)
 -- >>> import Debug.SimpleReflect.Vars
 -- >>> import Data.Void
+-- >>> import Data.List (sort)
 -- >>> import System.Timeout (timeout)
 -- >>> let timingOut :: NFData a => a -> IO a; timingOut = fmap (fromMaybe (error "timeout")) . timeout (5*10^6) . evaluate . force
 
@@ -503,6 +510,9 @@
 -- >>> (a,b,c) & partsOf each .~ [x,y]
 -- (x,y,c)
 --
+-- >>> ('b', 'a', 'd', 'c') & partsOf each %~ sort
+-- ('a','b','c','d')
+--
 -- So technically, this is only a 'Lens' if you do not change the number of results it returns.
 --
 -- When applied to a 'Fold' the result is merely a 'Getter'.
@@ -1003,7 +1013,23 @@
 -- | Traverse any 'Traversable' container. This is an 'IndexedTraversal' that is indexed by ordinal position.
 traversed :: Traversable f => IndexedTraversal Int (f a) (f b) a b
 traversed = conjoined traverse (indexing traverse)
-{-# INLINE traversed #-}
+{-# INLINE [0] traversed #-}
+
+imapList :: (Int -> a -> b) -> [a] -> [b]
+imapList f = go 0
+  where
+    go i (x:xs) = f i x : go (i+1) xs
+    go _ []     = []
+{-# INLINE imapList #-}
+
+{-# RULES
+"traversed -> mapped"     traversed = sets fmap          :: Functor f => ASetter (f a) (f b) a b;
+"traversed -> folded"     traversed = folded             :: Foldable f => Getting (Endo r) (f a) a;
+"traversed -> ifolded"    traversed = folded             :: Foldable f => IndexedGetting Int (Endo r) (f a) a;
+"traversed -> imapList"   traversed = isets imapList     :: AnIndexedSetter Int [a] [b] a b;
+"traversed -> imapSeq"    traversed = isets mapWithIndex :: AnIndexedSetter Int (Seq a) (Seq b) a b;
+"traversed -> imapVector" traversed = isets Vector.imap  :: AnIndexedSetter Int (Vector a) (Vector b) a b;
+ #-}
 
 -- | Traverse any 'Traversable1' container. This is an 'IndexedTraversal1' that is indexed by ordinal position.
 traversed1 :: Traversable1 f => IndexedTraversal1 Int (f a) (f b) a b
diff --git a/src/Data/Text/Lazy/Lens.hs b/src/Data/Text/Lazy/Lens.hs
--- a/src/Data/Text/Lazy/Lens.hs
+++ b/src/Data/Text/Lazy/Lens.hs
@@ -19,14 +19,22 @@
   , utf8
   ) where
 
-import Control.Lens
+import Control.Lens.Type
+import Control.Lens.Getter
+import Control.Lens.Fold
+import Control.Lens.Iso
+import Control.Lens.Prism
+import Control.Lens.Setter
+import Control.Lens.Traversal
 import Data.ByteString.Lazy as ByteString
+import Data.Monoid
 import Data.Text.Lazy as Text
 import Data.Text.Lazy.Builder
 import Data.Text.Lazy.Encoding
 
 -- $setup
 -- >>> :set -XOverloadedStrings
+-- >>> import Control.Lens
 
 -- | This isomorphism can be used to 'pack' (or 'unpack') lazy 'Text'.
 --
@@ -102,7 +110,22 @@
 -- can be more efficient.
 text :: IndexedTraversal' Int Text Char
 text = unpacked . traversed
-{-# INLINE text #-}
+{-# INLINE [0] text #-}
+
+{-# RULES
+"lazy text -> map"    text = sets Text.map        :: ASetter' Text Char;
+"lazy text -> imap"   text = isets imapLazy       :: AnIndexedSetter' Int Text Char;
+"lazy text -> foldr"  text = foldring Text.foldr  :: Getting (Endo r) Text Char;
+"lazy text -> ifoldr" text = ifoldring ifoldrLazy :: IndexedGetting Int (Endo r) Text Char;
+ #-}
+
+imapLazy :: (Int -> Char -> Char) -> Text -> Text
+imapLazy f = snd . Text.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
+{-# INLINE imapLazy #-}
+
+ifoldrLazy :: (Int -> Char -> a -> a) -> a -> Text -> a
+ifoldrLazy f z xs = Text.foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldrLazy #-}
 
 -- | Encode/Decode a lazy 'Text' to/from lazy 'ByteString', via UTF-8.
 --
diff --git a/src/Data/Text/Lens.hs b/src/Data/Text/Lens.hs
--- a/src/Data/Text/Lens.hs
+++ b/src/Data/Text/Lens.hs
@@ -18,13 +18,18 @@
   , _Text
   ) where
 
-import           Control.Lens
+import           Control.Lens.Type
+import           Control.Lens.Iso
+import           Control.Lens.Traversal
 import           Data.Text as Strict
 import qualified Data.Text.Strict.Lens as Strict
 import           Data.Text.Lazy as Lazy
 import qualified Data.Text.Lazy.Lens as Lazy
 import           Data.Text.Lazy.Builder
 
+-- $setup
+-- >>> import Control.Lens
+
 -- | Traversals for strict or lazy 'Text'
 class IsText t where
   -- | This isomorphism can be used to 'pack' (or 'unpack') strict or lazy 'Text'.
@@ -55,7 +60,7 @@
 instance IsText String where
   packed = id
   {-# INLINE packed #-}
-  text = indexing traverse
+  text = traversed
   {-# INLINE text #-}
   builder = Lazy.packed . builder
   {-# INLINE builder #-}
@@ -104,3 +109,4 @@
   {-# INLINE builder #-}
   text = Lazy.text
   {-# INLINE text #-}
+
diff --git a/src/Data/Text/Strict/Lens.hs b/src/Data/Text/Strict/Lens.hs
--- a/src/Data/Text/Strict/Lens.hs
+++ b/src/Data/Text/Strict/Lens.hs
@@ -18,15 +18,23 @@
   , _Text
   ) where
 
-import Control.Lens
+import Control.Lens.Type
+import Control.Lens.Getter
+import Control.Lens.Fold
+import Control.Lens.Iso
+import Control.Lens.Prism
+import Control.Lens.Setter
+import Control.Lens.Traversal
 import Data.ByteString (ByteString)
-import Data.Text
+import Data.Monoid
+import Data.Text as Strict
 import Data.Text.Encoding
 import Data.Text.Lazy (toStrict)
 import Data.Text.Lazy.Builder
 
 -- $setup
 -- >>> :set -XOverloadedStrings
+-- >>> import Control.Lens
 
 -- | This isomorphism can be used to 'pack' (or 'unpack') strict 'Text'.
 --
@@ -98,7 +106,22 @@
 -- be more efficient.
 text :: IndexedTraversal' Int Text Char
 text = unpacked . traversed
-{-# INLINE text #-}
+{-# INLINE [0] text #-}
+
+{-# RULES
+"strict text -> map"    text = sets Strict.map        :: ASetter' Text Char;
+"strict text -> imap"   text = isets imapStrict       :: AnIndexedSetter' Int Text Char;
+"strict text -> foldr"  text = foldring Strict.foldr  :: Getting (Endo r) Text Char;
+"strict text -> ifoldr" text = ifoldring ifoldrStrict :: IndexedGetting Int (Endo r) Text Char;
+ #-}
+
+imapStrict :: (Int -> Char -> Char) -> Text -> Text
+imapStrict f = snd . Strict.mapAccumL (\i a -> i `seq` (i + 1, f i a)) 0
+{-# INLINE imapStrict #-}
+
+ifoldrStrict :: (Int -> Char -> a -> a) -> a -> Text -> a
+ifoldrStrict f z xs = Strict.foldr (\ x g i -> i `seq` f i x (g (i+1))) (const z) xs 0
+{-# INLINE ifoldrStrict #-}
 
 -- | Encode/Decode a strict 'Text' to/from strict 'ByteString', via UTF-8.
 --
diff --git a/src/Data/Vector/Generic/Lens.hs b/src/Data/Vector/Generic/Lens.hs
--- a/src/Data/Vector/Generic/Lens.hs
+++ b/src/Data/Vector/Generic/Lens.hs
@@ -30,10 +30,18 @@
   -- * Traversal of individual indices
   , ordinals
   , vectorIx
+  , vectorTraverse
   ) where
 
 import Control.Applicative
-import Control.Lens
+import Control.Lens.Type
+import Control.Lens.Lens
+import Control.Lens.Getter
+import Control.Lens.Fold
+import Control.Lens.Iso
+import Control.Lens.Indexed
+import Control.Lens.Setter
+import Control.Lens.Traversal
 import Control.Lens.Internal.List (ordinalNub)
 import Data.Monoid
 import Data.Vector.Generic as V hiding (zip, filter, indexed)
@@ -122,6 +130,18 @@
   | 0 <= i && i < V.length v = f (v V.! i) <&> \a -> v V.// [(i, a)]
   | otherwise                = pure v
 {-# INLINE vectorIx #-}
+
+-- | Indexed vector traversal for a generic vector.
+vectorTraverse :: (V.Vector v a, V.Vector w b) => IndexedTraversal Int (v a) (w b) a b
+vectorTraverse f v = V.fromListN (V.length v) <$> traversed f (V.toList v)
+{-# INLINE [0] vectorTraverse #-}
+
+{-# RULES
+"vectorTraverse -> mapped" vectorTraverse  = sets V.map         :: (V.Vector v a, V.Vector v b) => ASetter (v a) (v b) a b;
+"vectorTraverse -> imapped" vectorTraverse = isets V.imap       :: (V.Vector v a, V.Vector v b) => AnIndexedSetter Int (v a) (v b) a b;
+"vectorTraverse -> foldr"  vectorTraverse  = foldring V.foldr   :: V.Vector v a => Getting (Endo r) (v a) a;
+"vectorTraverse -> ifoldr" vectorTraverse  = ifoldring V.ifoldr :: V.Vector v a => IndexedGetting Int (Endo r) (v a) a;
+ #-}
 
 -- | Different vector implementations are isomorphic to each other.
 converted :: (Vector v a, Vector w a, Vector v b, Vector w b) => Iso (v a) (v b) (w a) (w b)
