Add new `Data.Bifunctor` module (re #9682)
authorHerbert Valerio Riedel <hvr@gnu.org>
Sun, 26 Oct 2014 07:49:38 +0000 (08:49 +0100)
committerHerbert Valerio Riedel <hvr@gnu.org>
Sun, 26 Oct 2014 07:50:46 +0000 (08:50 +0100)
This adds the module `Data.Bifunctor` providing the
`Bifunctor(bimap,first,second)` class and a couple of instances

This module and the class were previously exported by the `bifunctors`
package.  In contrast to the original module all `INLINE` pragmas have
been removed.

Reviewed By: ekmett, austin, dolio

Differential Revision: https://phabricator.haskell.org/D336

libraries/base/Data/Bifunctor.hs [new file with mode: 0644]
libraries/base/base.cabal
libraries/base/changelog.md

diff --git a/libraries/base/Data/Bifunctor.hs b/libraries/base/Data/Bifunctor.hs
new file mode 100644 (file)
index 0000000..4c84f1c
--- /dev/null
@@ -0,0 +1,103 @@
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE NoImplicitPrelude #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- 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 Data.Either          ( Either(..) )
+import GHC.Base             ( (.), id )
+
+-- | 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@
+    bimap :: (a -> b) -> (c -> d) -> p a c -> p b d
+    bimap f g = first f . second g
+
+    -- | Map covariantly over the first argument.
+    --
+    -- @'first' f ≡ 'bimap' f 'id'@
+    first :: (a -> b) -> p a c -> p b c
+    first f = bimap f id
+
+    -- | Map covariantly over the second argument.
+    --
+    -- @'second' ≡ 'bimap' 'id'@
+    second :: (b -> c) -> p a b -> p a c
+    second = bimap id
+
+
+instance Bifunctor (,) where
+    bimap f g ~(a, b) = (f a, g b)
+
+instance Bifunctor ((,,) x1) where
+    bimap f g ~(x1, a, b) = (x1, f a, g b)
+
+instance Bifunctor ((,,,) x1 x2) where
+    bimap f g ~(x1, x2, a, b) = (x1, x2, f a, g b)
+
+instance Bifunctor ((,,,,) x1 x2 x3) where
+    bimap f g ~(x1, x2, x3, a, b) = (x1, x2, x3, f a, g b)
+
+instance Bifunctor ((,,,,,) x1 x2 x3 x4) where
+    bimap f g ~(x1, x2, x3, x4, a, b) = (x1, x2, x3, x4, f a, g b)
+
+instance Bifunctor ((,,,,,,) x1 x2 x3 x4 x5) where
+    bimap f g ~(x1, x2, x3, x4, x5, a, b) = (x1, x2, x3, x4, x5, f a, g b)
+
+
+instance Bifunctor Either where
+    bimap f _ (Left a) = Left (f a)
+    bimap _ g (Right b) = Right (g b)
+
+instance Bifunctor Const where
+    bimap f _ (Const a) = Const (f a)
index 45e674f..957053d 100644 (file)
@@ -117,6 +117,7 @@ Library
         Control.Monad.ST.Strict
         Control.Monad.ST.Unsafe
         Control.Monad.Zip
+        Data.Bifunctor
         Data.Bits
         Data.Bool
         Data.Char
index ed93b46..76fe87a 100644 (file)
@@ -84,6 +84,9 @@
 
   * Remove deprecated `Data.OldTypeable` (#9639)
 
+  * New module `Data.Bifunctor` providing the `Bifunctor(bimap,first,second)`
+    class (previously defined in `bifunctors` package) (#9682)
+
 ## 4.7.0.1  *Jul 2014*
 
   * Bundled with GHC 7.8.3