    -- | This module contains lenses and traversals for common structures in Haskell.
    -- It also contains the combinators for lenses and traversals.
    module Lens.Family.Stock (
    -- * Lens Combinators
        choosing
      , alongside
      , beside
    -- * Stock Lenses
      , _1, _2
      , chosen
      , ix
      , at, intAt
      , at', intAt'
      , contains, intContains
    -- * Stock Traversals
      , both
      , _Left, _Right
      , _Just, _Nothing
      , ignored
    -- * Stock SECs
      , mapped
    -- * Types
      , AlongsideLeft, AlongsideRight
    -- * Re-exports
      , LensLike, LensLike'
      , Applicative, Identical
      ) where

    import Control.Arrow (first, second)
    import Control.Applicative (Applicative, pure, (<$>), (<*>))
    import Lens.Family (LensLike, LensLike')
    import Lens.Family.Unchecked (lens, setting, Identical)
    import Lens.Family.Phantom (Phantom, coerce)
    import qualified Data.Map as Map
    import qualified Data.IntMap as IntMap
    import qualified Data.Map.Strict as Map'
    import qualified Data.IntMap.Strict as IntMap'
    import qualified Data.Set as Set
    import qualified Data.IntSet as IntSet

    choosing :: Functor f => LensLike f a a' c c' -> LensLike f b b' c c' -> LensLike f (Either a b) (Either a' b') c c'
    -- ^ @
    -- choosing :: Lens a a' c c' -> Lens b b' c c' -> Lens (Either a b) (Either a' b') c c'
    -- @
    --
    -- @
    -- choosing :: Traversal a a' c c' -> Traversal b b' c c' -> Traversal (Either a b) (Either a' b') c c'
    -- @
    --
    -- @
    -- choosing :: Getter a a' c c' -> Getter b b' c c' -> Getter (Either a b) (Either a' b') c c'
    -- @
    --
    -- @
    -- choosing :: Fold a a' c c' -> Fold b b' c c' -> Fold (Either a b) (Either a' b') c c'
    -- @
    --
    -- @
    -- choosing :: Setter a a' c c' -> Setter b b' c c' -> Setter (Either a b) (Either a' b') c c'
    -- @
    --
    -- Given two lens\/traversal\/getter\/fold\/setter families with the same substructure, make a new lens\/traversal\/getter\/fold\/setter on 'Either'.
    choosing la _  f (Left a)  = Left  `fmap` la f a
    choosing _  lb f (Right b) = Right `fmap` lb f b

    _1 :: Functor f => LensLike f (a, b) (a', b) a a'
    -- ^ @
    -- _1 :: Lens (a, b) (a', b) a a'
    -- @
    --
    -- Lens on the first element of a pair.
    _1 f (a, b) = (\a' -> (a', b)) `fmap` f a

    _2 :: Functor f => LensLike f (a, b) (a, b') b b'
    -- ^ @
    -- _2 :: Lens (a, b) (a, b') b b'
    -- @
    --
    -- Lens on the second element of a pair.
    _2 f (a, b) = (\b' -> (a, b')) `fmap` f b

    chosen :: Functor f => LensLike f (Either a a) (Either b b) a b
    -- ^ @
    -- chosen :: Lens (Either a a) (Either b b) a b
    -- @
    --
    -- Lens on the Left or Right element of an ('Either' a a).
    chosen = choosing id id

    ix :: (Eq k, Functor f) => k -> LensLike' f (k -> v) v
    -- ^ @
    -- ix :: Eq k => k -> Lens' (k -> v) v
    -- @
    --
    -- Lens on a given point of a function.
    ix k f g = (\v' x -> if (k == x) then v' else g x) `fmap` f (g k)

    at :: (Ord k, Functor f) => k -> LensLike' f (Map.Map k v) (Maybe v)
    -- ^ @
    -- at :: Ord k => k -> Lens' (Map.Map k v) (Maybe v)
    -- @
    --
    -- Lens on a given point of a 'Map.Map'.
    at = flip Map.alterF

    intAt :: Functor f => Int -> LensLike' f (IntMap.IntMap v) (Maybe v)
    -- ^ @
    -- intAt :: Int -> Lens (IntMap.IntMap v) (Maybe v)
    -- @
    --
    -- Lens on a given point of a 'IntMap.IntMap'.
    intAt = flip IntMap.alterF

    at' :: (Ord k, Functor f) => k -> LensLike' f (Map.Map k v) (Maybe v)
    -- ^ @
    -- at :: Ord k => k -> Lens' (Map.Map k v) (Maybe v)
    -- @
    --
    -- Lens providing strict access to a given point of a 'Map.Map'.
    at' = flip Map'.alterF

    intAt' :: Functor f => Int -> LensLike' f (IntMap.IntMap v) (Maybe v)
    -- ^ @
    -- intAt :: Int -> Lens (IntMap.IntMap v) (Maybe v)
    -- @
    --
    -- Lens providing strict access to a given point of a 'IntMap.IntMap'.
    intAt' = flip IntMap'.alterF

    contains :: (Ord k, Functor f) => k -> LensLike' f (Set.Set k) Bool
    -- ^ @
    -- contains :: Ord => k -> Lens' (Set.Set k) Bool
    -- @
    --
    -- Lens on a given point of a 'Set.Set'.
    contains k = lens (Set.member k) (\m nv -> if nv then Set.insert k m else Set.delete k m)

    intContains :: Functor f => Int -> LensLike' f IntSet.IntSet Bool
    -- ^ @
    -- intContains :: Int -> Lens' IntSet.IntSet Bool
    -- @
    --
    -- Lens on a given point of a 'IntSet.IntSet'.
    intContains k = lens (IntSet.member k) (\m nv -> if nv then IntSet.insert k m else IntSet.delete k m)

    _Left :: Applicative f => LensLike f (Either a b) (Either a' b) a a'
    -- ^ @
    -- _Left :: Traversal (Either a b) (Either a' b) a a'
    -- @
    --
    -- Traversal on the 'Left' element of an 'Either'.
    _Left f (Left a) = Left <$> f a
    _Left _ (Right b) = pure (Right b)

    _Right :: Applicative f => LensLike f (Either a b) (Either a b') b b'
    -- ^ @
    -- _Right :: Traversal (Either a b) (Either a b') b b'
    -- @
    --
    -- Traversal on the 'Right' element of an 'Either'.
    _Right f (Right b) = Right <$> f b
    _Right _ (Left a) = pure (Left a)

    _Just :: Applicative f => LensLike f (Maybe a) (Maybe a') a a'
    -- ^ @
    -- _Just :: Traversal (Maybe a) (Maybe a') a a'
    -- @
    --
    -- Traversal on the 'Just' element of a 'Maybe'.
    _Just f (Just a) = Just <$> f a
    _Just _ Nothing = pure Nothing

    _Nothing :: Applicative f => LensLike' f (Maybe a) ()
    -- ^ @
    -- _Nothing :: Traversal' (Maybe a) ()
    -- @
    --
    -- Traversal on the 'Nothing' element of a 'Maybe'.
    _Nothing f Nothing = const Nothing <$> f ()
    _Nothing _ j = pure j

    both :: Applicative f => LensLike f (a,a) (b,b) a b
    -- ^ @
    -- both :: Traversal (a,a) (b,b) a b
    -- @
    --
    -- Traversals on both elements of a pair @(a,a)@.
    both f (x,y) = (,) <$> f x <*> f y

    beside :: Applicative f => LensLike f a a' c c' -> LensLike f b b' c c' -> LensLike f (a,b) (a',b') c c'
    -- ^ @
    -- beside :: Traversal a a' c c' -> Traversal b' b' c c' -> Traversal (a,b) (a',b') c c'
    -- @
    --
    -- @
    -- beside :: Fold a a' c c' -> Fold b' b' c c' -> Fold (a,b) (a',b') c c'
    -- @
    --
    -- @
    -- beside :: Setter a a' c c' -> Setter b' b' c c' -> Setter (a,b) (a',b') c c'
    -- @
    --
    -- Given two traversals\/folds\/setters referencing a type 'c', create a traversal\/fold\/setter on the pair referencing 'c'.
    beside la lb f (x,y) = (,) <$> la f x <*> lb f y

    ignored :: Applicative f => null -> a -> f a
    -- ^ @
    -- ignored :: Traversal a a b b'
    -- @
    --
    -- The empty traversal on any type.
    ignored _ = pure

    mapped :: (Identical f, Functor g) => LensLike f (g a) (g a') a a'
    -- ^ @
    -- mapped :: Functor g => Setter (g a) (g a') a a'
    -- @
    --
    -- An SEC referencing the parameter of a functor.
    mapped = setting fmap

    {- Alongside -}

    newtype AlongsideLeft f b a = AlongsideLeft (f (a, b))

    instance Functor f => Functor (AlongsideLeft f a) where
      fmap f (AlongsideLeft x) = AlongsideLeft (fmap (first f) x)

    instance Phantom f => Phantom (AlongsideLeft f a) where
      coerce (AlongsideLeft x) = AlongsideLeft (coerce x)

    newtype AlongsideRight f a b = AlongsideRight (f (a, b))

    instance Functor f => Functor (AlongsideRight f a) where
      fmap f (AlongsideRight x) = AlongsideRight (fmap (second f) x)

    instance Phantom f => Phantom (AlongsideRight f a) where
      coerce (AlongsideRight x) = AlongsideRight (coerce x)

    alongside :: Functor f => LensLike (AlongsideLeft f b2') a1 a1' b1 b1'
                           -> LensLike (AlongsideRight f a1') a2 a2' b2 b2'
                           -> LensLike f (a1, a2) (a1', a2') (b1, b2) (b1', b2')
    -- ^ @
    -- alongside :: Lens a1 a1' b1 b1' -> Lens a2 a2' b2 b2' -> Lens (a1, a2) (a1', a2') (b1, b2) (b1', b2')
    -- @
    --
    -- @
    -- alongside :: Getter a1 a1' b1 b1' -> Getter a2 a2' b2 b2' -> Getter (a1, a2) (a1', a2') (b1, b2) (b1', b2')
    -- @
    --
    -- Given two lens\/getter families, make a new lens\/getter on their product.
    alongside l1 l2 f (a1, a2) = fa1'a2'
     where
      AlongsideRight fa1'a2' = l2 f2 a2
      f2 b2 = AlongsideRight fa1'b2'
       where
        AlongsideLeft fa1'b2' = l1 f1 a1
        f1 b1 = AlongsideLeft (f (b1, b2))