content: {-# LANGUAGE LinearTypes #-}
  {-# LANGUAGE TypeOperators #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  {-# OPTIONS_HADDOCK hide #-}
  
  module Data.Bifunctor.Linear.Internal.Bifunctor
    ( Bifunctor (..),
    )
  where
  
  import Prelude.Linear
  
  -- | The Bifunctor class
  --
  -- == Laws
  --
  -- If 'bimap' is supplied, then
  -- @'bimap' 'id' 'id' = 'id'@
  --
  -- * If 'first' and 'second' are supplied, then
  -- @
  -- 'first' 'id' ≡ 'id'
  -- 'second' 'id' ≡ 'id'
  -- @
  --
  -- * If all are supplied, then
  -- @'bimap' f g = 'first' f '.' 'second' g
  class Bifunctor p where
    {-# MINIMAL bimap | (first, second) #-}
    bimap :: (a %1 -> b) -> (c %1 -> d) -> a `p` c %1 -> b `p` d
    bimap f g x = first f (second g x)
    {-# INLINE bimap #-}
  
    first :: (a %1 -> b) -> a `p` c %1 -> b `p` c
    first f = bimap f id
    {-# INLINE first #-}
  
    second :: (b %1 -> c) -> a `p` b %1 -> a `p` c
    second = bimap id
    {-# INLINE second #-}
  
  -- # Instances
  -------------------------------------------------------------------------------
  
  instance Bifunctor (,) where
    bimap f g (x, y) = (f x, g y)
    first f (x, y) = (f x, y)
    second g (x, y) = (x, g y)
  
  instance Bifunctor Either where
    bimap f g = either (Left . f) (Right . g)
  