diff --git a/CHANGELOG.md b/CHANGELOG.md
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -1,3 +1,8 @@
+# unreleased (0.3.0.0)
+
+* Moved `Lens.Micro.Classes` into `Lens.Micro.Internal`.
+* Added `<%~`, `<<%~`, `<<.~`.
+
 # 0.2.0.0
 
 * Removed `toListOf`.
diff --git a/microlens.cabal b/microlens.cabal
--- a/microlens.cabal
+++ b/microlens.cabal
@@ -1,5 +1,5 @@
 name:                microlens
-version:             0.2.0.0
+version:             0.3.0.0
 synopsis:            A tiny part of the lens library which you can depend upon
 description:
   This is an extract from <http://hackage.haskell.org/package/lens lens> (with no dependencies). It's not a toy lenses library, unsuitable for “real world”, but merely a small one. It is compatible with lens, and should have same performance. It also has better documentation.
@@ -16,9 +16,11 @@
   .
     * if you think lenses compose “in the wrong order” (in which case you're looking for <http://hackage.haskell.org/package/fclabels fclabels>)
   .
-  Note that microlens has /no/ dependencies starting from GHC 7.10 (base-4.8). Prior to that, it has to depend on transformers-0.2 or above.
+  If you're writing an application which uses lenses more extnesively, look at <http://hackage.haskell.org/package/microlens-platform microlens-platform> – it combines features of all other microlens packages (<http://hackage.haskell.org/package/microlens-mtl microlens-mtl>, <http://hackage.haskell.org/package/microlens-th microlens-th>, <http://hackage.haskell.org/package/microlens-ghc microlens-ghc>).
   .
-  Also note that it's not done yet and there's a lot of things missing.
+  There's a longer readme <https://github.com/aelve/microlens#readme on Github>, you should read it if you're still interested about using this library.
+  .
+  Note that microlens has /no/ dependencies starting from GHC 7.10 (base-4.8). Prior to that, it has to depend on transformers-0.2 or above.
 license:             BSD3
 license-file:        LICENSE
 author:              Artyom
@@ -38,7 +40,6 @@
 
 library
   exposed-modules:     Lens.Micro
-                       Lens.Micro.Classes
                        Lens.Micro.Internal
                        Lens.Micro.Type
   -- other-modules:       
diff --git a/src/Lens/Micro.hs b/src/Lens/Micro.hs
--- a/src/Lens/Micro.hs
+++ b/src/Lens/Micro.hs
@@ -18,6 +18,7 @@
   sets,
   (%~), over,
   (.~), set,
+  (<%~), (<<%~), (<<.~),
   mapped,
 
   -- * Getting (retrieving a value)
@@ -45,6 +46,7 @@
   traversed,
   each,
   ix,
+  _head, _tail, _init, _last,
 
   -- * Prisms (traversals iterating over at most 1 element)
   -- $prisms-note
@@ -54,11 +56,11 @@
 where
 
 
-import Lens.Micro.Classes
 import Lens.Micro.Type
 import Lens.Micro.Internal
 
 import Control.Applicative
+import Control.Monad
 import Data.Functor.Identity
 import Data.Monoid
 
@@ -153,7 +155,7 @@
 (10,"20")
 -}
 over :: ASetter s t a b -> (a -> b) -> s -> t
-over l f = runIdentity . l (Identity . f)
+over l f = runIdentity #. l (Identity #. f)
 {-# INLINE over #-}
 
 {- |
@@ -193,7 +195,7 @@
 @
 -}
 set :: ASetter s t a b -> b -> s -> t
-set l b = runIdentity . l (\_ -> Identity b)
+set l b = runIdentity #. l (\_ -> Identity b)
 {-# INLINE set #-}
 
 {- |
@@ -214,6 +216,57 @@
 mapped = sets fmap
 {-# INLINE mapped #-}
 
+{- |
+This is a version of ('%~') which modifies the structure and returns it along with the new value:
+
+>>> (1, 2) & _1 <%~ negate
+(-1, (-1, 2))
+
+Simpler type signatures:
+
+@
+('<%~') ::             'Lens' s t a b      -> (a -> b) -> s -> (b, t)
+('<%~') :: 'Monoid' b => 'Traversal' s t a b -> (a -> b) -> s -> (b, t)
+@
+-}
+(<%~) :: ((a -> (b, b)) -> s -> (b, t)) -> (a -> b) -> s -> (b, t)
+(<%~) l f = l (join (,) . f)
+{-# INLINE (<%~) #-}
+
+{- |
+This is a version of ('%~') which modifies the structure and returns it along with the old value:
+
+>>> (1, 2) & _1 <<%~ negate
+(1, (-1, 2))
+
+Simpler type signatures:
+
+@
+('<<%~') ::             'Lens' s t a b      -> (a -> b) -> s -> (a, t)
+('<<%~') :: 'Monoid' a => 'Traversal' s t a b -> (a -> b) -> s -> (a, t)
+@
+-}
+(<<%~) :: ((a -> (a, b)) -> s -> (a, t)) -> (a -> b) -> s -> (a, t)
+(<<%~) l f = l (\a -> (a, f a))
+{-# INLINE (<<%~) #-}
+
+{- |
+This is a version of ('.~') which modifies the structure and returns it along with the old value:
+
+>>> (1, 2) & _1 <<.~ 0
+(1, (0, 2))
+
+Simpler type signatures:
+
+@
+('<<.~') ::             'Lens' s t a b      -> b -> s -> (a, t)
+('<<.~') :: 'Monoid' a => 'Traversal' s t a b -> b -> s -> (a, t)
+@
+-}
+(<<.~) :: ((a -> (a, b)) -> s -> (a, t)) -> b -> s -> (a, t)
+(<<.~) l x = l (\a -> (a, x))
+{-# INLINE (<<.~) #-}
+
 -- Getting -----------------------------------------------------------------
 
 {- $getters-note
@@ -241,6 +294,8 @@
 "string"
 
 The reason for this is that traversals use 'Applicative', and the 'Applicative' instance for 'Const' uses monoid concatenation to combine “effects” of 'Const'.
+
+A non-operator version of ('^.') is called @view@, and it's not included in this package because it is a bit more general (it works in @MonadReader@ and thus requires a <http://hackage.haskell.org/package/mtl mtl> dependency). You can get it from <http://hackage.haskell.org/package/microlens-mtl microlens-mtl>.
 -}
 (^.) :: s -> Getting a s a -> a
 s ^. l = getConst (l Const s)
@@ -318,9 +373,11 @@
 
 >>> Right 1 ^? _Right
 Just 1
+
+A non-operator version of ('^?') is called @preview@, and – like @view@ – it's not included in this package because it's more general and requires a <http://hackage.haskell.org/package/mtl mtl> dependency). As with @view@, you can get it from <http://hackage.haskell.org/package/microlens-mtl microlens-mtl>.
 -}
 (^?) :: s -> Getting (First a) s a -> Maybe a
-s ^? l = getFirst (foldMapOf l (First . Just) s)
+s ^? l = getFirst (foldMapOf l (First #. Just) s)
 {-# INLINE (^?) #-}
 
 infixl 8 ^?
@@ -348,7 +405,7 @@
 True
 -}
 has :: Getting Any s a -> s -> Bool
-has l = getAny . foldMapOf l (\_ -> Any True)
+has l = getAny #. foldMapOf l (\_ -> Any True)
 {-# INLINE has #-}
 
 -- Lenses ------------------------------------------------------------------
@@ -397,6 +454,82 @@
 both :: Traversal (a, a) (b, b) a b
 both f = \ ~(a, b) -> liftA2 (,) (f a) (f b)
 {-# INLINE both #-}
+
+{- |
+'_head' traverses the 1st element of something (usually a list, but can also be a @Seq@, etc):
+
+>>> [1..5] ^? _head
+Just 1
+
+It can be used to modify too, as in this example where the 1st letter of a sentence is capitalised:
+
+>>> "mary had a little lamb." & _head %~ toTitle
+"Mary had a little lamb."
+
+The reason it's a traversal and not a lens is that there's nothing to traverse when the list is empty:
+
+>>> [] ^? _head
+Nothing
+
+This package only lets you use '_head' on lists, but you can import @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package and get instances for @ByteString@ and @Seq@.
+-}
+_head :: Cons s s a a => Traversal' s a
+_head = _Cons._1
+{-# INLINE _head #-}
+
+{- |
+'_tail' gives you access to the tail of a list (or @Seq@, etc):
+
+>>> [1..5] ^? _tail
+Just [2,3,4,5]
+
+You can modify the tail as well:
+
+>>> [4,1,2,3] & _tail %~ reverse
+[4,3,2,1]
+
+Since lists are monoids, you can use '_tail' with plain ('^.') (and then it'll return an empty list if you give it an empty list):
+
+>>> [1..5] ^. _tail
+[2,3,4,5]
+
+>>> [] ^. _tail
+[]
+
+If you want to traverse each /element/ of the tail, use '_tail' with 'each':
+
+>>> "I HATE CAPS." & _tail.each %~ toLower
+"I hate caps."
+
+This package only lets you use '_tail' on lists, but you can import @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package and get instances for @ByteString@ and @Seq@.
+-}
+_tail :: Cons s s a a => Traversal' s s
+_tail = _Cons._2
+{-# INLINE _tail #-}
+
+{- |
+'_init' gives you access to all-but-the-last elements of the list:
+
+>>> "Hello." ^. _init
+"Hello"
+
+See documentation for '_tail', as '_init' and '_tail' are pretty similar.
+-}
+_init :: Snoc s s a a => Traversal' s s
+_init = _Snoc._1
+{-# INLINE _init #-}
+
+{- |
+'_last' gives you access to the last element of the list:
+
+>>> "Hello." ^? _last
+'.'
+
+See documentation for '_head', as '_last' and '_head' are pretty similar.
+-}
+_last :: Snoc s s a a => Traversal' s a
+_last = _Snoc._2
+{-# INLINE _last #-}
 
 -- Prisms ------------------------------------------------------------------
 
diff --git a/src/Lens/Micro/Classes.hs b/src/Lens/Micro/Classes.hs
deleted file mode 100644
--- a/src/Lens/Micro/Classes.hs
+++ /dev/null
@@ -1,398 +0,0 @@
-{-# LANGUAGE
-CPP,
-MultiParamTypeClasses,
-FunctionalDependencies,
-RankNTypes,
-TypeFamilies,
-KindSignatures,
-FlexibleInstances,
-UndecidableInstances,
-DefaultSignatures
-  #-}
-
-
-module Lens.Micro.Classes
-(
-  Each(..),
-  Index,
-  IxValue,
-  Ixed(..),
-  At(..),
-  Field1(..),
-  Field2(..),
-  Field3(..),
-  Field4(..),
-  Field5(..),
-)
-where
-
-
-import Lens.Micro.Type
-import Lens.Micro.Internal
-
-#if __GLASGOW_HASKELL__ < 710
-import Data.Traversable
-import Control.Applicative
-#endif
-
-import Data.Complex
-
-
-class Each s t a b | s -> a, t -> b, s b -> t, t a -> s where
-  {- |
-'each' tries to be a universal 'Traversal' – it behaves like 'traversed' in most situations, but also adds support for e.g. tuples with same-typed values:
-
->>> (1,2) & each %~ succ
-(2,3)
-
->>> ["x", "y", "z"] ^. each
-"xyz"
-
-However, note that 'each' doesn't work on /every/ instance of 'Traversable'. If you have a 'Traversable' which isn't supported by 'each', you can use 'traversed' instead. Personally, I like using 'each' instead of 'traversed' whenever possible – it's shorter and more descriptive.
-
-You can use 'each' with these things:
-
-@
-'each' :: 'Traversal' [a] [b] a b
-
-'each' :: 'Traversal' ('Maybe' a) ('Maybe' b) a b
-
-'each' :: 'Traversal' (a,a) (b,b) a b
-'each' :: 'Traversal' (a,a,a) (b,b,b) a b
-'each' :: 'Traversal' (a,a,a,a) (b,b,b,b) a b
-'each' :: 'Traversal' (a,a,a,a,a) (b,b,b,b,b) a b
-
-'each' :: ('RealFloat' a, 'RealFloat' b) => 'Traversal' ('Complex' a) ('Complex' b) a b
-@
-
-Additionally, you can use 'each' with types from <http://hackage.haskell.org/package/array array>, <http://hackage.haskell.org/package/bytestring bytestring>, and <http://hackage.haskell.org/package/containers containers> by importing @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package.
-  -}
-  each :: Traversal s t a b
-  default each :: (Traversable g, s ~ g a, t ~ g b) => Traversal s t a b
-  each = traverse
-
-instance (a~b, q~r) => Each (a,b) (q,r) a q where
-  each f ~(a,b) = (,) <$> f a <*> f b
-  {-# INLINE each #-}
-
-instance (a~b, a~c, q~r, q~s) => Each (a,b,c) (q,r,s) a q where
-  each f ~(a,b,c) = (,,) <$> f a <*> f b <*> f c
-  {-# INLINE each #-}
-
-instance (a~b, a~c, a~d, q~r, q~s, q~t) => Each (a,b,c,d) (q,r,s,t) a q where
-  each f ~(a,b,c,d) = (,,,) <$> f a <*> f b <*> f c <*> f d
-  {-# INLINE each #-}
-
-instance (a~b, a~c, a~d, a~e, q~r, q~s, q~t, q~u) => Each (a,b,c,d,e) (q,r,s,t,u) a q where
-  each f ~(a,b,c,d,e) = (,,,,) <$> f a <*> f b <*> f c <*> f d <*> f e
-  {-# INLINE each #-}
-
-instance Each (Complex a) (Complex b) a b where
-  each f (a :+ b) = (:+) <$> f a <*> f b
-  {-# INLINE each #-}
-
-instance Each [a] [b] a b where
-  each = traversed
-  {-# INLINE each #-}
-
-instance Each (Maybe a) (Maybe b) a b
-
-type family Index (s :: *) :: *
-
-type family IxValue (m :: *) :: *
-
-type instance Index   (e -> a) = e
-type instance IxValue (e -> a) = a
-type instance Index   [a] = Int
-type instance IxValue [a] = a
-
-class Ixed m where
-  {- |
-This traversal lets you access (and update) an arbitrary element in a list, array, @Map@, etc. (If you want to insert or delete elements as well, look at 'at'.)
-
-An example for lists:
-
->>> [0..5] & ix 3 .~ 10
-[0,1,2,100,4,5]
-
-You can use it for getting, too:
-
->>> [0..5] ^? ix 3
-Just 3
-
-Of course, the element may not be present (which means that you can use 'ix' as a safe variant of ('!!')):
-
->>> [0..5] ^? ix 10
-Nothing
-
-Another useful instance is the one for functions – it lets you modify their outputs for specific inputs. For instance, here's 'maximum' that returns 0 when the list is empty (instead of throwing an exception):
-
-@
-maximum0 = 'maximum' 'Lens.Micro.&' 'ix' [] 'Lens.Micro..~' 0
-@
-
-The following instances are provided in this package:
-
-@
-'ix' :: 'Int' -> 'Traversal'' [a] a
-
-'ix' :: ('Eq' e) => e -> 'Traversal'' (e -> a) a
-@
-
-Additionally, you can use 'ix' with types from <http://hackage.haskell.org/package/array array>, <http://hackage.haskell.org/package/bytestring bytestring>, and <http://hackage.haskell.org/package/containers containers> by importing @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package.
-  -}
-  ix :: Index m -> Traversal' m (IxValue m)
-  default ix :: (At m) => Index m -> Traversal' m (IxValue m)
-  ix = ixAt
-  {-# INLINE ix #-}
-
-class Ixed m => At m where
-  {- |
-This lens lets you read, write, or delete elements in @Map@-like structures. It returns 'Nothing' when the value isn't found, just like @lookup@:
-
-@
-Data.Map.lookup k m = m 'Lens.Micro.^.' at k
-@
-
-However, it also lets you insert and delete values by setting the value to @'Just' value@ or 'Nothing':
-
-@
-Data.Map.insert k a m = m 'Lens.Micro.&' at k 'Lens.Micro..~' Just a
-
-Data.Map.delete k m = m 'Lens.Micro.&' at k 'Lens.Micro..~' Nothing
-@
-
-'at' doesn't work for arrays, because you can't delete an arbitrary element from an array.
-
-If you want to modify an already existing value, you should use 'ix' instead because then you won't have to deal with 'Maybe' ('ix' is available for all types that have 'at').
-
-This package doesn't actually provide any instances for 'at', but you can import @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package and get instances for @Map@ and @IntMap@.
-  -}
-  at :: Index m -> Lens' m (Maybe (IxValue m))
-
-ixAt :: At m => Index m -> Traversal' m (IxValue m)
-ixAt i = at i . traverse
-{-# INLINE ixAt #-}
-
-instance Eq e => Ixed (e -> a) where
-  ix e p f = (\a e' -> if e == e' then a else f e') <$> p (f e)
-  {-# INLINE ix #-}
-
-instance Ixed [a] where
-  ix k f xs0 | k < 0     = pure xs0
-             | otherwise = go xs0 k where
-    go [] _ = pure []
-    go (a:as) 0 = (:as) <$> f a
-    go (a:as) i = (a:) <$> (go as $! i - 1)
-  {-# INLINE ix #-}
-
-class Field1 s t a b | s -> a, t -> b, s b -> t, t a -> s where
-  {- |
-Gives access to the 1st field of a tuple (up to 5-tuples).
-
-Getting the 1st component:
-
->>> (1,2,3,4,5) ^. _1
-1
-
-Setting the 1st component:
-
->>> (1,2,3) & _1 .~ 10
-(10,2,3)
-
-Note that this lens is lazy, and can set fields even of 'undefined':
-
->>> set _1 10 undefined :: (Int, Int)
-(10,*** Exception: Prelude.undefined
-
-This is done to avoid violating a lens law stating that you can get back what you put:
-
->>> view _1 . set _1 10 $ (undefined :: (Int, Int))
-10
-
-The implementation (for 2-tuples) is:
-
-@
-'_1' f t = (,) '<$>' f    ('fst' t)
-             '<*>' 'pure' ('snd' t)
-@
-
-or, alternatively,
-
-@
-'_1' f ~(a,b) = (\\a' -> (a',b)) '<$>' f a
-@
-
-(where @~@ means a <https://wiki.haskell.org/Lazy_pattern_match lazy pattern>).
-
-'_2', '_3', '_4', and '_5' are also available (see below).
-  -}
-  _1 :: Lens s t a b
-
-instance Field1 (a,b) (a',b) a a' where
-  _1 k ~(a,b) = (\a' -> (a',b)) <$> k a
-  {-# INLINE _1 #-}
-
-instance Field1 (a,b,c) (a',b,c) a a' where
-  _1 k ~(a,b,c) = (\a' -> (a',b,c)) <$> k a
-  {-# INLINE _1 #-}
-
-instance Field1 (a,b,c,d) (a',b,c,d) a a' where
-  _1 k ~(a,b,c,d) = (\a' -> (a',b,c,d)) <$> k a
-  {-# INLINE _1 #-}
-
-instance Field1 (a,b,c,d,e) (a',b,c,d,e) a a' where
-  _1 k ~(a,b,c,d,e) = (\a' -> (a',b,c,d,e)) <$> k a
-  {-# INLINE _1 #-}
-
-{-
-
-instance Field1 (a,b,c,d,e,f) (a',b,c,d,e,f) a a' where
-  _1 k ~(a,b,c,d,e,f) = (\a' -> (a',b,c,d,e,f)) <$> k a
-  {-# INLINE _1 #-}
-
-instance Field1 (a,b,c,d,e,f,g) (a',b,c,d,e,f,g) a a' where
-  _1 k ~(a,b,c,d,e,f,g) = (\a' -> (a',b,c,d,e,f,g)) <$> k a
-  {-# INLINE _1 #-}
-
-instance Field1 (a,b,c,d,e,f,g,h) (a',b,c,d,e,f,g,h) a a' where
-  _1 k ~(a,b,c,d,e,f,g,h) = (\a' -> (a',b,c,d,e,f,g,h)) <$> k a
-  {-# INLINE _1 #-}
-
-instance Field1 (a,b,c,d,e,f,g,h,i) (a',b,c,d,e,f,g,h,i) a a' where
-  _1 k ~(a,b,c,d,e,f,g,h,i) = (\a' -> (a',b,c,d,e,f,g,h,i)) <$> k a
-  {-# INLINE _1 #-}
-
--}
-
-class Field2 s t a b | s -> a, t -> b, s b -> t, t a -> s where
-  _2 :: Lens s t a b
-
-instance Field2 (a,b) (a,b') b b' where
-  _2 k ~(a,b) = (\b' -> (a,b')) <$> k b
-  {-# INLINE _2 #-}
-
-instance Field2 (a,b,c) (a,b',c) b b' where
-  _2 k ~(a,b,c) = (\b' -> (a,b',c)) <$> k b
-  {-# INLINE _2 #-}
-
-instance Field2 (a,b,c,d) (a,b',c,d) b b' where
-  _2 k ~(a,b,c,d) = (\b' -> (a,b',c,d)) <$> k b
-  {-# INLINE _2 #-}
-
-instance Field2 (a,b,c,d,e) (a,b',c,d,e) b b' where
-  _2 k ~(a,b,c,d,e) = (\b' -> (a,b',c,d,e)) <$> k b
-  {-# INLINE _2 #-}
-
-{-
-
-instance Field2 (a,b,c,d,e,f) (a,b',c,d,e,f) b b' where
-  _2 k ~(a,b,c,d,e,f) = (\b' -> (a,b',c,d,e,f)) <$> k b
-  {-# INLINE _2 #-}
-
-instance Field2 (a,b,c,d,e,f,g) (a,b',c,d,e,f,g) b b' where
-  _2 k ~(a,b,c,d,e,f,g) = (\b' -> (a,b',c,d,e,f,g)) <$> k b
-  {-# INLINE _2 #-}
-
-instance Field2 (a,b,c,d,e,f,g,h) (a,b',c,d,e,f,g,h) b b' where
-  _2 k ~(a,b,c,d,e,f,g,h) = (\b' -> (a,b',c,d,e,f,g,h)) <$> k b
-  {-# INLINE _2 #-}
-
-instance Field2 (a,b,c,d,e,f,g,h,i) (a,b',c,d,e,f,g,h,i) b b' where
-  _2 k ~(a,b,c,d,e,f,g,h,i) = (\b' -> (a,b',c,d,e,f,g,h,i)) <$> k b
-  {-# INLINE _2 #-}
-
--}
-
-class Field3 s t a b | s -> a, t -> b, s b -> t, t a -> s where
-  _3 :: Lens s t a b
-
-instance Field3 (a,b,c) (a,b,c') c c' where
-  _3 k ~(a,b,c) = (\c' -> (a,b,c')) <$> k c
-  {-# INLINE _3 #-}
-
-instance Field3 (a,b,c,d) (a,b,c',d) c c' where
-  _3 k ~(a,b,c,d) = (\c' -> (a,b,c',d)) <$> k c
-  {-# INLINE _3 #-}
-
-instance Field3 (a,b,c,d,e) (a,b,c',d,e) c c' where
-  _3 k ~(a,b,c,d,e) = (\c' -> (a,b,c',d,e)) <$> k c
-  {-# INLINE _3 #-}
-
-{-
-
-instance Field3 (a,b,c,d,e,f) (a,b,c',d,e,f) c c' where
-  _3 k ~(a,b,c,d,e,f) = (\c' -> (a,b,c',d,e,f)) <$> k c
-  {-# INLINE _3 #-}
-
-instance Field3 (a,b,c,d,e,f,g) (a,b,c',d,e,f,g) c c' where
-  _3 k ~(a,b,c,d,e,f,g) = (\c' -> (a,b,c',d,e,f,g)) <$> k c
-  {-# INLINE _3 #-}
-
-instance Field3 (a,b,c,d,e,f,g,h) (a,b,c',d,e,f,g,h) c c' where
-  _3 k ~(a,b,c,d,e,f,g,h) = (\c' -> (a,b,c',d,e,f,g,h)) <$> k c
-  {-# INLINE _3 #-}
-
-instance Field3 (a,b,c,d,e,f,g,h,i) (a,b,c',d,e,f,g,h,i) c c' where
-  _3 k ~(a,b,c,d,e,f,g,h,i) = (\c' -> (a,b,c',d,e,f,g,h,i)) <$> k c
-  {-# INLINE _3 #-}
-
--}
-
-class Field4 s t a b | s -> a, t -> b, s b -> t, t a -> s where
-  _4 :: Lens s t a b
-
-instance Field4 (a,b,c,d) (a,b,c,d') d d' where
-  _4 k ~(a,b,c,d) = (\d' -> (a,b,c,d')) <$> k d
-  {-# INLINE _4 #-}
-
-instance Field4 (a,b,c,d,e) (a,b,c,d',e) d d' where
-  _4 k ~(a,b,c,d,e) = (\d' -> (a,b,c,d',e)) <$> k d
-  {-# INLINE _4 #-}
-
-{-
-
-instance Field4 (a,b,c,d,e,f) (a,b,c,d',e,f) d d' where
-  _4 k ~(a,b,c,d,e,f) = (\d' -> (a,b,c,d',e,f)) <$> k d
-  {-# INLINE _4 #-}
-
-instance Field4 (a,b,c,d,e,f,g) (a,b,c,d',e,f,g) d d' where
-  _4 k ~(a,b,c,d,e,f,g) = (\d' -> (a,b,c,d',e,f,g)) <$> k d
-  {-# INLINE _4 #-}
-
-instance Field4 (a,b,c,d,e,f,g,h) (a,b,c,d',e,f,g,h) d d' where
-  _4 k ~(a,b,c,d,e,f,g,h) = (\d' -> (a,b,c,d',e,f,g,h)) <$> k d
-  {-# INLINE _4 #-}
-
-instance Field4 (a,b,c,d,e,f,g,h,i) (a,b,c,d',e,f,g,h,i) d d' where
-  _4 k ~(a,b,c,d,e,f,g,h,i) = (\d' -> (a,b,c,d',e,f,g,h,i)) <$> k d
-  {-# INLINE _4 #-}
-
--}
-
-class Field5 s t a b | s -> a, t -> b, s b -> t, t a -> s where
-  _5 :: Lens s t a b
-
-instance Field5 (a,b,c,d,e) (a,b,c,d,e') e e' where
-  _5 k ~(a,b,c,d,e) = (\e' -> (a,b,c,d,e')) <$> k e
-  {-# INLINE _5 #-}
-
-{-
-
-instance Field5 (a,b,c,d,e,f) (a,b,c,d,e',f) e e' where
-  _5 k ~(a,b,c,d,e,f) = (\e' -> (a,b,c,d,e',f)) <$> k e
-  {-# INLINE _5 #-}
-
-instance Field5 (a,b,c,d,e,f,g) (a,b,c,d,e',f,g) e e' where
-  _5 k ~(a,b,c,d,e,f,g) = (\e' -> (a,b,c,d,e',f,g)) <$> k e
-  {-# INLINE _5 #-}
-
-instance Field5 (a,b,c,d,e,f,g,h) (a,b,c,d,e',f,g,h) e e' where
-  _5 k ~(a,b,c,d,e,f,g,h) = (\e' -> (a,b,c,d,e',f,g,h)) <$> k e
-  {-# INLINE _5 #-}
-
-instance Field5 (a,b,c,d,e,f,g,h,i) (a,b,c,d,e',f,g,h,i) e e' where
-  _5 k ~(a,b,c,d,e,f,g,h,i) = (\e' -> (a,b,c,d,e',f,g,h,i)) <$> k e
-  {-# INLINE _5 #-}
-
--}
diff --git a/src/Lens/Micro/Internal.hs b/src/Lens/Micro/Internal.hs
--- a/src/Lens/Micro/Internal.hs
+++ b/src/Lens/Micro/Internal.hs
@@ -2,12 +2,23 @@
 CPP,
 FlexibleContexts,
 FlexibleInstances,
+UndecidableInstances,
 RankNTypes,
-ScopedTypeVariables
+ScopedTypeVariables,
+DefaultSignatures,
+KindSignatures,
+TypeFamilies,
+MultiParamTypeClasses,
+FunctionalDependencies
   #-}
 
+
 {- |
-This module is needed to give other packages from the microlens family (like <http://hackage.haskell.org/package/microlens-ghc microlens-ghc>) access to functions that don't need to be exported from "Lens.Micro" (because they just clutter the namespace). Also, okay, uh, e.g. 'traversed' is here because otherwise there'd be a dependency cycle.
+This module is needed to give other packages from the microlens family (like <http://hackage.haskell.org/package/microlens-ghc microlens-ghc>) access to functions and classes that don't need to be exported from "Lens.Micro" (because they just clutter the namespace). Also, okay, uh, e.g. 'traversed' is here because otherwise there'd be a dependency cycle.
+
+Classes like 'Each', 'Ixed', etc are provided for convenience – you're not supposed to export functions that work on all members of 'Ixed', for instance. Only microlens can do that. You mustn't declare instances of those classes for other types, either; these classes are incompatible with lens's classes, and by doing so you would divide the ecosystem.
+
+If you absolutely need to define an instance (e.g. for internal use), only do it for your own types, because otherwise I might add an instance to one of the microlens packages later and if our instances are different it might lead to subtle bugs.
 -}
 module Lens.Micro.Internal
 (
@@ -19,16 +30,29 @@
   sets,
   ( #. ),
   ( .# ),
+  Each(..),
+  Index,
+  IxValue,
+  Ixed(..),
+  At(..),
+  Field1(..),
+  Field2(..),
+  Field3(..),
+  Field4(..),
+  Field5(..),
+  Cons(..),
+  Snoc(..),
 )
 where
 
 
 import Lens.Micro.Type
 
-import Data.Functor.Identity
-import Data.Monoid
 import Control.Applicative
+import Data.Monoid
 import Data.Foldable as F
+import Data.Functor.Identity
+import Data.Complex
 
 #if __GLASGOW_HASKELL__ < 710
 import Data.Traversable
@@ -93,7 +117,7 @@
 
 -- was renamed from “coerce”
 phantom :: Const r a -> Const r b
-phantom = Const . getConst
+phantom = Const #. getConst
 {-# INLINE phantom #-}
 
 noEffect :: Applicative (Const r) => Const r a
@@ -117,3 +141,389 @@
 ( .# ) :: (b -> c) -> (a -> b) -> (a -> c)
 ( .# ) pbc _ = unsafeCoerce pbc
 #endif
+
+------------------------------------------------------------------------------
+-- classes
+------------------------------------------------------------------------------
+
+class Each s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  {- |
+'each' tries to be a universal 'Traversal' – it behaves like 'traversed' in most situations, but also adds support for e.g. tuples with same-typed values:
+
+>>> (1,2) & each %~ succ
+(2,3)
+
+>>> ["x", "y", "z"] ^. each
+"xyz"
+
+However, note that 'each' doesn't work on /every/ instance of 'Traversable'. If you have a 'Traversable' which isn't supported by 'each', you can use 'traversed' instead. Personally, I like using 'each' instead of 'traversed' whenever possible – it's shorter and more descriptive.
+
+You can use 'each' with these things:
+
+@
+'each' :: 'Traversal' [a] [b] a b
+
+'each' :: 'Traversal' ('Maybe' a) ('Maybe' b) a b
+
+'each' :: 'Traversal' (a,a) (b,b) a b
+'each' :: 'Traversal' (a,a,a) (b,b,b) a b
+'each' :: 'Traversal' (a,a,a,a) (b,b,b,b) a b
+'each' :: 'Traversal' (a,a,a,a,a) (b,b,b,b,b) a b
+
+'each' :: ('RealFloat' a, 'RealFloat' b) => 'Traversal' ('Complex' a) ('Complex' b) a b
+@
+
+Additionally, you can use 'each' with types from <http://hackage.haskell.org/package/array array>, <http://hackage.haskell.org/package/bytestring bytestring>, and <http://hackage.haskell.org/package/containers containers> by importing @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package.
+  -}
+  each :: Traversal s t a b
+  default each :: (Traversable g, s ~ g a, t ~ g b) => Traversal s t a b
+  each = traverse
+
+instance (a~b, q~r) => Each (a,b) (q,r) a q where
+  each f ~(a,b) = (,) <$> f a <*> f b
+  {-# INLINE each #-}
+
+instance (a~b, a~c, q~r, q~s) => Each (a,b,c) (q,r,s) a q where
+  each f ~(a,b,c) = (,,) <$> f a <*> f b <*> f c
+  {-# INLINE each #-}
+
+instance (a~b, a~c, a~d, q~r, q~s, q~t) => Each (a,b,c,d) (q,r,s,t) a q where
+  each f ~(a,b,c,d) = (,,,) <$> f a <*> f b <*> f c <*> f d
+  {-# INLINE each #-}
+
+instance (a~b, a~c, a~d, a~e, q~r, q~s, q~t, q~u) => Each (a,b,c,d,e) (q,r,s,t,u) a q where
+  each f ~(a,b,c,d,e) = (,,,,) <$> f a <*> f b <*> f c <*> f d <*> f e
+  {-# INLINE each #-}
+
+instance Each (Complex a) (Complex b) a b where
+  each f (a :+ b) = (:+) <$> f a <*> f b
+  {-# INLINE each #-}
+
+instance Each [a] [b] a b where
+  each = traversed
+  {-# INLINE each #-}
+
+instance Each (Maybe a) (Maybe b) a b
+
+type family Index (s :: *) :: *
+
+type family IxValue (m :: *) :: *
+
+type instance Index   (e -> a) = e
+type instance IxValue (e -> a) = a
+type instance Index   [a] = Int
+type instance IxValue [a] = a
+
+class Ixed m where
+  {- |
+This traversal lets you access (and update) an arbitrary element in a list, array, @Map@, etc. (If you want to insert or delete elements as well, look at 'at'.)
+
+An example for lists:
+
+>>> [0..5] & ix 3 .~ 10
+[0,1,2,10,4,5]
+
+You can use it for getting, too:
+
+>>> [0..5] ^? ix 3
+Just 3
+
+Of course, the element may not be present (which means that you can use 'ix' as a safe variant of ('!!')):
+
+>>> [0..5] ^? ix 10
+Nothing
+
+Another useful instance is the one for functions – it lets you modify their outputs for specific inputs. For instance, here's 'maximum' that returns 0 when the list is empty (instead of throwing an exception):
+
+@
+maximum0 = 'maximum' 'Lens.Micro.&' 'ix' [] 'Lens.Micro..~' 0
+@
+
+The following instances are provided in this package:
+
+@
+'ix' :: 'Int' -> 'Traversal'' [a] a
+
+'ix' :: ('Eq' e) => e -> 'Traversal'' (e -> a) a
+@
+
+Additionally, you can use 'ix' with types from <http://hackage.haskell.org/package/array array>, <http://hackage.haskell.org/package/bytestring bytestring>, and <http://hackage.haskell.org/package/containers containers> by importing @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package.
+  -}
+  ix :: Index m -> Traversal' m (IxValue m)
+  default ix :: (At m) => Index m -> Traversal' m (IxValue m)
+  ix = ixAt
+  {-# INLINE ix #-}
+
+class Ixed m => At m where
+  {- |
+This lens lets you read, write, or delete elements in @Map@-like structures. It returns 'Nothing' when the value isn't found, just like @lookup@:
+
+@
+Data.Map.lookup k m = m 'Lens.Micro.^.' at k
+@
+
+However, it also lets you insert and delete values by setting the value to @'Just' value@ or 'Nothing':
+
+@
+Data.Map.insert k a m = m 'Lens.Micro.&' at k 'Lens.Micro..~' Just a
+
+Data.Map.delete k m = m 'Lens.Micro.&' at k 'Lens.Micro..~' Nothing
+@
+
+'at' doesn't work for arrays, because you can't delete an arbitrary element from an array.
+
+If you want to modify an already existing value, you should use 'ix' instead because then you won't have to deal with 'Maybe' ('ix' is available for all types that have 'at').
+
+Note that 'at' isn't strict for @Map@, even if you're using @Data.Map.Strict@:
+
+>>> Data.Map.Strict.size (Data.Map.Strict.empty & at 1 .~ Just undefined)
+1
+
+The reason for such behavior is that there's actually no “strict @Map@” type; @Data.Map.Strict@ just provides some strict functions for ordinary @Map@s.
+
+This package doesn't actually provide any instances for 'at', but you can import @Lens.Micro.GHC@ from the <http://hackage.haskell.org/package/microlens-ghc microlens-ghc> package and get instances for @Map@ and @IntMap@.
+  -}
+  at :: Index m -> Lens' m (Maybe (IxValue m))
+
+ixAt :: At m => Index m -> Traversal' m (IxValue m)
+ixAt i = at i . traverse
+{-# INLINE ixAt #-}
+
+instance Eq e => Ixed (e -> a) where
+  ix e p f = (\a e' -> if e == e' then a else f e') <$> p (f e)
+  {-# INLINE ix #-}
+
+instance Ixed [a] where
+  ix k f xs0 | k < 0     = pure xs0
+             | otherwise = go xs0 k where
+    go [] _ = pure []
+    go (a:as) 0 = (:as) <$> f a
+    go (a:as) i = (a:) <$> (go as $! i - 1)
+  {-# INLINE ix #-}
+
+class Field1 s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  {- |
+Gives access to the 1st field of a tuple (up to 5-tuples).
+
+Getting the 1st component:
+
+>>> (1,2,3,4,5) ^. _1
+1
+
+Setting the 1st component:
+
+>>> (1,2,3) & _1 .~ 10
+(10,2,3)
+
+Note that this lens is lazy, and can set fields even of 'undefined':
+
+>>> set _1 10 undefined :: (Int, Int)
+(10,*** Exception: Prelude.undefined
+
+This is done to avoid violating a lens law stating that you can get back what you put:
+
+>>> view _1 . set _1 10 $ (undefined :: (Int, Int))
+10
+
+The implementation (for 2-tuples) is:
+
+@
+'_1' f t = (,) '<$>' f    ('fst' t)
+             '<*>' 'pure' ('snd' t)
+@
+
+or, alternatively,
+
+@
+'_1' f ~(a,b) = (\\a' -> (a',b)) '<$>' f a
+@
+
+(where @~@ means a <https://wiki.haskell.org/Lazy_pattern_match lazy pattern>).
+
+'_2', '_3', '_4', and '_5' are also available (see below).
+  -}
+  _1 :: Lens s t a b
+
+instance Field1 (a,b) (a',b) a a' where
+  _1 k ~(a,b) = (\a' -> (a',b)) <$> k a
+  {-# INLINE _1 #-}
+
+instance Field1 (a,b,c) (a',b,c) a a' where
+  _1 k ~(a,b,c) = (\a' -> (a',b,c)) <$> k a
+  {-# INLINE _1 #-}
+
+instance Field1 (a,b,c,d) (a',b,c,d) a a' where
+  _1 k ~(a,b,c,d) = (\a' -> (a',b,c,d)) <$> k a
+  {-# INLINE _1 #-}
+
+instance Field1 (a,b,c,d,e) (a',b,c,d,e) a a' where
+  _1 k ~(a,b,c,d,e) = (\a' -> (a',b,c,d,e)) <$> k a
+  {-# INLINE _1 #-}
+
+{-
+
+instance Field1 (a,b,c,d,e,f) (a',b,c,d,e,f) a a' where
+  _1 k ~(a,b,c,d,e,f) = (\a' -> (a',b,c,d,e,f)) <$> k a
+  {-# INLINE _1 #-}
+
+instance Field1 (a,b,c,d,e,f,g) (a',b,c,d,e,f,g) a a' where
+  _1 k ~(a,b,c,d,e,f,g) = (\a' -> (a',b,c,d,e,f,g)) <$> k a
+  {-# INLINE _1 #-}
+
+instance Field1 (a,b,c,d,e,f,g,h) (a',b,c,d,e,f,g,h) a a' where
+  _1 k ~(a,b,c,d,e,f,g,h) = (\a' -> (a',b,c,d,e,f,g,h)) <$> k a
+  {-# INLINE _1 #-}
+
+instance Field1 (a,b,c,d,e,f,g,h,i) (a',b,c,d,e,f,g,h,i) a a' where
+  _1 k ~(a,b,c,d,e,f,g,h,i) = (\a' -> (a',b,c,d,e,f,g,h,i)) <$> k a
+  {-# INLINE _1 #-}
+
+-}
+
+class Field2 s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  _2 :: Lens s t a b
+
+instance Field2 (a,b) (a,b') b b' where
+  _2 k ~(a,b) = (\b' -> (a,b')) <$> k b
+  {-# INLINE _2 #-}
+
+instance Field2 (a,b,c) (a,b',c) b b' where
+  _2 k ~(a,b,c) = (\b' -> (a,b',c)) <$> k b
+  {-# INLINE _2 #-}
+
+instance Field2 (a,b,c,d) (a,b',c,d) b b' where
+  _2 k ~(a,b,c,d) = (\b' -> (a,b',c,d)) <$> k b
+  {-# INLINE _2 #-}
+
+instance Field2 (a,b,c,d,e) (a,b',c,d,e) b b' where
+  _2 k ~(a,b,c,d,e) = (\b' -> (a,b',c,d,e)) <$> k b
+  {-# INLINE _2 #-}
+
+{-
+
+instance Field2 (a,b,c,d,e,f) (a,b',c,d,e,f) b b' where
+  _2 k ~(a,b,c,d,e,f) = (\b' -> (a,b',c,d,e,f)) <$> k b
+  {-# INLINE _2 #-}
+
+instance Field2 (a,b,c,d,e,f,g) (a,b',c,d,e,f,g) b b' where
+  _2 k ~(a,b,c,d,e,f,g) = (\b' -> (a,b',c,d,e,f,g)) <$> k b
+  {-# INLINE _2 #-}
+
+instance Field2 (a,b,c,d,e,f,g,h) (a,b',c,d,e,f,g,h) b b' where
+  _2 k ~(a,b,c,d,e,f,g,h) = (\b' -> (a,b',c,d,e,f,g,h)) <$> k b
+  {-# INLINE _2 #-}
+
+instance Field2 (a,b,c,d,e,f,g,h,i) (a,b',c,d,e,f,g,h,i) b b' where
+  _2 k ~(a,b,c,d,e,f,g,h,i) = (\b' -> (a,b',c,d,e,f,g,h,i)) <$> k b
+  {-# INLINE _2 #-}
+
+-}
+
+class Field3 s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  _3 :: Lens s t a b
+
+instance Field3 (a,b,c) (a,b,c') c c' where
+  _3 k ~(a,b,c) = (\c' -> (a,b,c')) <$> k c
+  {-# INLINE _3 #-}
+
+instance Field3 (a,b,c,d) (a,b,c',d) c c' where
+  _3 k ~(a,b,c,d) = (\c' -> (a,b,c',d)) <$> k c
+  {-# INLINE _3 #-}
+
+instance Field3 (a,b,c,d,e) (a,b,c',d,e) c c' where
+  _3 k ~(a,b,c,d,e) = (\c' -> (a,b,c',d,e)) <$> k c
+  {-# INLINE _3 #-}
+
+{-
+
+instance Field3 (a,b,c,d,e,f) (a,b,c',d,e,f) c c' where
+  _3 k ~(a,b,c,d,e,f) = (\c' -> (a,b,c',d,e,f)) <$> k c
+  {-# INLINE _3 #-}
+
+instance Field3 (a,b,c,d,e,f,g) (a,b,c',d,e,f,g) c c' where
+  _3 k ~(a,b,c,d,e,f,g) = (\c' -> (a,b,c',d,e,f,g)) <$> k c
+  {-# INLINE _3 #-}
+
+instance Field3 (a,b,c,d,e,f,g,h) (a,b,c',d,e,f,g,h) c c' where
+  _3 k ~(a,b,c,d,e,f,g,h) = (\c' -> (a,b,c',d,e,f,g,h)) <$> k c
+  {-# INLINE _3 #-}
+
+instance Field3 (a,b,c,d,e,f,g,h,i) (a,b,c',d,e,f,g,h,i) c c' where
+  _3 k ~(a,b,c,d,e,f,g,h,i) = (\c' -> (a,b,c',d,e,f,g,h,i)) <$> k c
+  {-# INLINE _3 #-}
+
+-}
+
+class Field4 s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  _4 :: Lens s t a b
+
+instance Field4 (a,b,c,d) (a,b,c,d') d d' where
+  _4 k ~(a,b,c,d) = (\d' -> (a,b,c,d')) <$> k d
+  {-# INLINE _4 #-}
+
+instance Field4 (a,b,c,d,e) (a,b,c,d',e) d d' where
+  _4 k ~(a,b,c,d,e) = (\d' -> (a,b,c,d',e)) <$> k d
+  {-# INLINE _4 #-}
+
+{-
+
+instance Field4 (a,b,c,d,e,f) (a,b,c,d',e,f) d d' where
+  _4 k ~(a,b,c,d,e,f) = (\d' -> (a,b,c,d',e,f)) <$> k d
+  {-# INLINE _4 #-}
+
+instance Field4 (a,b,c,d,e,f,g) (a,b,c,d',e,f,g) d d' where
+  _4 k ~(a,b,c,d,e,f,g) = (\d' -> (a,b,c,d',e,f,g)) <$> k d
+  {-# INLINE _4 #-}
+
+instance Field4 (a,b,c,d,e,f,g,h) (a,b,c,d',e,f,g,h) d d' where
+  _4 k ~(a,b,c,d,e,f,g,h) = (\d' -> (a,b,c,d',e,f,g,h)) <$> k d
+  {-# INLINE _4 #-}
+
+instance Field4 (a,b,c,d,e,f,g,h,i) (a,b,c,d',e,f,g,h,i) d d' where
+  _4 k ~(a,b,c,d,e,f,g,h,i) = (\d' -> (a,b,c,d',e,f,g,h,i)) <$> k d
+  {-# INLINE _4 #-}
+
+-}
+
+class Field5 s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  _5 :: Lens s t a b
+
+instance Field5 (a,b,c,d,e) (a,b,c,d,e') e e' where
+  _5 k ~(a,b,c,d,e) = (\e' -> (a,b,c,d,e')) <$> k e
+  {-# INLINE _5 #-}
+
+{-
+
+instance Field5 (a,b,c,d,e,f) (a,b,c,d,e',f) e e' where
+  _5 k ~(a,b,c,d,e,f) = (\e' -> (a,b,c,d,e',f)) <$> k e
+  {-# INLINE _5 #-}
+
+instance Field5 (a,b,c,d,e,f,g) (a,b,c,d,e',f,g) e e' where
+  _5 k ~(a,b,c,d,e,f,g) = (\e' -> (a,b,c,d,e',f,g)) <$> k e
+  {-# INLINE _5 #-}
+
+instance Field5 (a,b,c,d,e,f,g,h) (a,b,c,d,e',f,g,h) e e' where
+  _5 k ~(a,b,c,d,e,f,g,h) = (\e' -> (a,b,c,d,e',f,g,h)) <$> k e
+  {-# INLINE _5 #-}
+
+instance Field5 (a,b,c,d,e,f,g,h,i) (a,b,c,d,e',f,g,h,i) e e' where
+  _5 k ~(a,b,c,d,e,f,g,h,i) = (\e' -> (a,b,c,d,e',f,g,h,i)) <$> k e
+  {-# INLINE _5 #-}
+
+-}
+
+class Cons s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  _Cons :: Traversal s t (a,s) (b,t)
+
+instance Cons [a] [b] a b where
+  _Cons f (a:as) = uncurry (:) <$> f (a, as)
+  _Cons _ []     = pure []
+  {-# INLINE _Cons #-}
+
+class Snoc s t a b | s -> a, t -> b, s b -> t, t a -> s where
+  _Snoc :: Traversal s t (s,a) (t,b)
+
+instance Snoc [a] [b] a b where
+  _Snoc _ [] = pure []
+  _Snoc f xs = (\(as,a) -> as ++ [a]) <$> f (init xs, last xs)
+  {-# INLINE _Snoc #-}
