    {-# LANGUAGE Safe #-}
    {-# LANGUAGE CPP #-}

    -----------------------------------------------------------------------------
    -- |
    -- Module      :  Data.Bifunctor
    -- Copyright   :  (C) 2008-2014 Edward Kmett,
    -- License     :  BSD-style (see the file LICENSE)
    --
    -- Maintainer  :  libraries@haskell.org
    -- Stability   :  provisional
    -- Portability :  portable
    --
    -- @since 4.8.0.0
    ----------------------------------------------------------------------------
    module Data.Bifunctor
      ( Bifunctor(..)
      ) where

    import Control.Applicative  ( Const(..) )
    import GHC.Generics ( K1(..) )

    -- $setup
    -- >>> import Prelude
    -- >>> import Data.Char (toUpper)

    -- | A bifunctor is a type constructor that takes
    -- two type arguments and is a functor in /both/ arguments. That
    -- is, unlike with 'Functor', a type constructor such as 'Either'
    -- does not need to be partially applied for a 'Bifunctor'
    -- instance, and the methods in this class permit mapping
    -- functions over the 'Left' value or the 'Right' value,
    -- or both at the same time.
    --
    -- Formally, the class 'Bifunctor' represents a bifunctor
    -- from @Hask@ -> @Hask@.
    --
    -- Intuitively it is a bifunctor where both the first and second
    -- arguments are covariant.
    --
    -- You can define a 'Bifunctor' by either defining 'bimap' or by
    -- defining both 'first' and 'second'.
    --
    -- If you supply 'bimap', you should ensure that:
    --
    -- @'bimap' 'id' 'id' ≡ 'id'@
    --
    -- If you supply 'first' and 'second', ensure:
    --
    -- @
    -- 'first' 'id' ≡ 'id'
    -- 'second' 'id' ≡ 'id'
    -- @
    --
    -- If you supply both, you should also ensure:
    --
    -- @'bimap' f g ≡ 'first' f '.' 'second' g@
    --
    -- These ensure by parametricity:
    --
    -- @
    -- 'bimap'  (f '.' g) (h '.' i) ≡ 'bimap' f h '.' 'bimap' g i
    -- 'first'  (f '.' g) ≡ 'first'  f '.' 'first'  g
    -- 'second' (f '.' g) ≡ 'second' f '.' 'second' g
    -- @
    --
    -- @since 4.8.0.0
    class Bifunctor p where
        {-# MINIMAL bimap | first, second #-}

        -- | Map over both arguments at the same time.
        --
        -- @'bimap' f g ≡ 'first' f '.' 'second' g@
        --
        -- ==== __Examples__
        -- >>> bimap toUpper (+1) ('j', 3)
        -- ('J',4)
        --
        -- >>> bimap toUpper (+1) (Left 'j')
        -- Left 'J'
        --
        -- >>> bimap toUpper (+1) (Right 3)
        -- Right 4
        bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
        bimap a -> b
    f c -> d
    g = (a -> b) -> p a d -> p b d
    forall (p :: * -> * -> *) a b c.
    Bifunctor p =>
    (a -> b) -> p a c -> p b c
    first a -> b
    f (p a d -> p b d) -> (p a c -> p a d) -> p a c -> p b d
    forall b c a. (b -> c) -> (a -> b) -> a -> c
    . (c -> d) -> p a c -> p a d
    forall (p :: * -> * -> *) b c a.
    Bifunctor p =>
    (b -> c) -> p a b -> p a c
    second c -> d
    g

        -- | Map covariantly over the first argument.
        --
        -- @'first' f ≡ 'bimap' f 'id'@
        --
        -- ==== __Examples__
        -- >>> first toUpper ('j', 3)
        -- ('J',3)
        --
        -- >>> first toUpper (Left 'j')
        -- Left 'J'
        first :: (a -> b) -> p a c -> p b c
        first a -> b
    f = (a -> b) -> (c -> c) -> p a c -> p b c
    forall (p :: * -> * -> *) a b c d.
    Bifunctor p =>
    (a -> b) -> (c -> d) -> p a c -> p b d
    bimap a -> b
    f c -> c
    forall a. a -> a
    id

        -- | Map covariantly over the second argument.
        --
        -- @'second' ≡ 'bimap' 'id'@
        --
        -- ==== __Examples__
        -- >>> second (+1) ('j', 3)
        -- ('j',4)
        --
        -- >>> second (+1) (Right 3)
        -- Right 4
        second :: (b -> c) -> p a b -> p a c
        second = (a -> a) -> (b -> c) -> p a b -> p a c
    forall (p :: * -> * -> *) a b c d.
    Bifunctor p =>
    (a -> b) -> (c -> d) -> p a c -> p b d
    bimap a -> a
    forall a. a -> a
    id

    -- | @since 4.8.0.0
    instance Bifunctor (,) where
        bimap :: forall a b c d. (a -> b) -> (c -> d) -> (a, c) -> (b, d)
    bimap a -> b
    f c -> d
    g ~(a
    a, c
    b) = (a -> b
    f a
    a, c -> d
    g c
    b)

    -- | @since 4.8.0.0
    instance Bifunctor ((,,) x1) where
        bimap :: forall a b c d. (a -> b) -> (c -> d) -> (x1, a, c) -> (x1, b, d)
    bimap a -> b
    f c -> d
    g ~(x1
    x1, a
    a, c
    b) = (x1
    x1, a -> b
    f a
    a, c -> d
    g c
    b)

    -- | @since 4.8.0.0
    instance Bifunctor ((,,,) x1 x2) where
        bimap :: forall a b c d.
    (a -> b) -> (c -> d) -> (x1, x2, a, c) -> (x1, x2, b, d)
    bimap a -> b
    f c -> d
    g ~(x1
    x1, x2
    x2, a
    a, c
    b) = (x1
    x1, x2
    x2, a -> b
    f a
    a, c -> d
    g c
    b)

    -- | @since 4.8.0.0
    instance Bifunctor ((,,,,) x1 x2 x3) where
        bimap :: forall a b c d.
    (a -> b) -> (c -> d) -> (x1, x2, x3, a, c) -> (x1, x2, x3, b, d)
    bimap a -> b
    f c -> d
    g ~(x1
    x1, x2
    x2, x3
    x3, a
    a, c
    b) = (x1
    x1, x2
    x2, x3
    x3, a -> b
    f a
    a, c -> d
    g c
    b)

    -- | @since 4.8.0.0
    instance Bifunctor ((,,,,,) x1 x2 x3 x4) where
        bimap :: forall a b c d.
    (a -> b)
    -> (c -> d) -> (x1, x2, x3, x4, a, c) -> (x1, x2, x3, x4, b, d)
    bimap a -> b
    f c -> d
    g ~(x1
    x1, x2
    x2, x3
    x3, x4
    x4, a
    a, c
    b) = (x1
    x1, x2
    x2, x3
    x3, x4
    x4, a -> b
    f a
    a, c -> d
    g c
    b)

    -- | @since 4.8.0.0
    instance Bifunctor ((,,,,,,) x1 x2 x3 x4 x5) where
        bimap :: forall a b c d.
    (a -> b)
    -> (c -> d)
    -> (x1, x2, x3, x4, x5, a, c)
    -> (x1, x2, x3, x4, x5, b, d)
    bimap a -> b
    f c -> d
    g ~(x1
    x1, x2
    x2, x3
    x3, x4
    x4, x5
    x5, a
    a, c
    b) = (x1
    x1, x2
    x2, x3
    x3, x4
    x4, x5
    x5, a -> b
    f a
    a, c -> d
    g c
    b)

    -- | @since 4.8.0.0
    instance Bifunctor Either where
        bimap :: forall a b c d. (a -> b) -> (c -> d) -> Either a c -> Either b d
    bimap a -> b
    f c -> d
    _ (Left a
    a) = b -> Either b d
    forall a b. a -> Either a b
    Left (a -> b
    f a
    a)
        bimap a -> b
    _ c -> d
    g (Right c
    b) = d -> Either b d
    forall a b. b -> Either a b
    Right (c -> d
    g c
    b)

    -- | @since 4.8.0.0
    instance Bifunctor Const where
        bimap :: forall a b c d. (a -> b) -> (c -> d) -> Const a c -> Const b d
    bimap a -> b
    f c -> d
    _ (Const a
    a) = b -> Const b d
    forall {k} a (b :: k). a -> Const a b
    Const (a -> b
    f a
    a)

    -- | @since 4.9.0.0
    instance Bifunctor (K1 i) where
        bimap :: forall a b c d. (a -> b) -> (c -> d) -> K1 i a c -> K1 i b d
    bimap a -> b
    f c -> d
    _ (K1 a
    c) = b -> K1 i b d
    forall k i c (p :: k). c -> K1 i c p
    K1 (a -> b
    f a
    c)