bifunctors 4.1.1 → 4.1.1.1
raw patch · 4 files changed
+218/−2 lines, 4 files
Files
- .travis.yml +45/−1
- bifunctors.cabal +1/−1
- src/Data/Bifoldable.hs +60/−0
- src/Data/Bitraversable.hs +112/−0
.travis.yml view
@@ -1,4 +1,5 @@-language: haskell+# See https://github.com/hvr/multi-ghc-travis for more information+ notifications: irc: channels:@@ -6,3 +7,46 @@ skip_join: true template: - "\x0313bifunctors\x03/\x0306%{branch}\x03 \x0314%{commit}\x03 %{build_url} %{message}"++env:+ # - GHCVER=7.0.1+ # - GHCVER=7.0.2+ # - GHCVER=7.0.3+ # - GHCVER=7.0.4+ # - GHCVER=7.2.1+ # - GHCVER=7.2.2+ - GHCVER=7.4.1+ - GHCVER=7.4.2+ - GHCVER=7.6.1+ - GHCVER=7.6.2+ - GHCVER=7.6.3+ - GHCVER=head++matrix:+ allow_failures:+ - env: GHCVER=head++before_install:+ - sudo add-apt-repository -y ppa:hvr/ghc+ - sudo apt-get update+ - sudo apt-get install cabal-install-1.18 ghc-$GHCVER+ - export PATH=/opt/ghc/$GHCVER/bin:$PATH++install:+ - cabal-1.18 update+ - cabal-1.18 install --only-dependencies --enable-tests++script:+ - cabal-1.18 configure --enable-tests -v2+ - cabal-1.18 build+ - cabal-1.18 test+ - cabal-1.18 check+ - cabal-1.18 sdist+ - export SRC_TGZ=$(cabal-1.18 info . | awk '{print $2 ".tar.gz";exit}') ;+ cd dist/;+ if [ -f "$SRC_TGZ" ]; then+ cabal-1.18 install "$SRC_TGZ";+ else+ echo "expected '$SRC_TGZ' not found";+ exit 1;+ fi
bifunctors.cabal view
@@ -1,6 +1,6 @@ name: bifunctors category: Data, Functors-version: 4.1.1+version: 4.1.1.1 license: BSD3 cabal-version: >= 1.6 license-file: LICENSE
src/Data/Bifoldable.hs view
@@ -32,19 +32,56 @@ import Data.Monoid import Data.Tagged +-- | Minimal definition either 'bifoldr' or 'bifoldMap'++-- | 'Bifoldable' identifies foldable structures with two different varieties of+-- elements. Common examples are 'Either' and '(,)':+--+-- > instance Bifoldable Either where+-- > bifoldMap f _ (Left a) = f a+-- > bifoldMap _ g (Right b) = g b+-- >+-- > instance Bifoldable (,) where+-- > bifoldr f g z (a, b) = f a (g b z)+--+-- When defining more than the minimal set of definitions, one should ensure+-- that the following identities hold:+--+-- @+-- 'bifold' ≡ 'bifoldMap' 'id' 'id'+-- 'bifoldMap' f g ≡ 'bifoldr' ('mappend' . f) ('mappend' . g) 'mempty'+-- 'bifoldr' f g z t ≡ 'appEndo' ('bifoldMap' (Endo . f) (Endo . g) t) z+-- @ class Bifoldable p where+ -- | Combines the elements of a structure using a monoid.+ --+ -- @'bifold' ≡ 'bifoldMap' 'id' 'id'@ bifold :: Monoid m => p m m -> m bifold = bifoldMap id id {-# INLINE bifold #-} + -- | Combines the elements of a structure, given ways of mapping them to a+ -- common monoid.+ --+ -- @'bifoldMap' f g ≡ 'bifoldr' ('mappend' . f) ('mappend' . g) 'mempty'@ bifoldMap :: Monoid m => (a -> m) -> (b -> m) -> p a b -> m bifoldMap f g = bifoldr (mappend . f) (mappend . g) mempty {-# INLINE bifoldMap #-} + -- | Combines the elements of a structure in a right associative manner. Given+ -- a hypothetical function @toEitherList :: p a b -> [Either a b]@ yielding a+ -- list of all elements of a structure in order, the following would hold:+ --+ -- @'bifoldr' f g z ≡ 'foldr' ('either' f g) z . toEitherList@ bifoldr :: (a -> c -> c) -> (b -> c -> c) -> c -> p a b -> c bifoldr f g z t = appEndo (bifoldMap (Endo . f) (Endo . g) t) z {-# INLINE bifoldr #-} + -- | Combines the elments of a structure in a left associative manner. Given a+ -- hypothetical function @toEitherList :: p a b -> [Either a b]@ yielding a+ -- list of all elements of a structure in order, the following would hold:+ --+ -- @'bifoldl' f g z ≡ 'foldl' (\acc -> 'either' (f acc) (g acc)) z . toEitherList@ bifoldl :: (c -> a -> c) -> (c -> b -> c) -> c -> p a b -> c bifoldl f g z t = appEndo (getDual (bifoldMap (Dual . Endo . flip f) (Dual . Endo . flip g) t)) z {-# INLINE bifoldl #-}@@ -78,70 +115,93 @@ bifoldMap _ g (Right b) = g b {-# INLINE bifoldMap #-} +-- | As 'bifoldr', but strict in the result of the reduction functions at each+-- step. bifoldr' :: Bifoldable t => (a -> c -> c) -> (b -> c -> c) -> c -> t a b -> c bifoldr' f g z0 xs = bifoldl f' g' id xs z0 where f' k x z = k $! f x z g' k x z = k $! g x z {-# INLINE bifoldr' #-} +-- | Right associative monadic bifold over a structure. bifoldrM :: (Bifoldable t, Monad m) => (a -> c -> m c) -> (b -> c -> m c) -> c -> t a b -> m c bifoldrM f g z0 xs = bifoldl f' g' return xs z0 where f' k x z = f x z >>= k g' k x z = g x z >>= k {-# INLINE bifoldrM #-} +-- | As 'bifoldl', but strict in the result of the reductionf unctions at each+-- step. bifoldl':: Bifoldable t => (a -> b -> a) -> (a -> c -> a) -> a -> t b c -> a bifoldl' f g z0 xs = bifoldr f' g' id xs z0 where f' x k z = k $! f z x g' x k z = k $! g z x {-# INLINE bifoldl' #-} +-- | Left associative monadic bifold over a structure. bifoldlM :: (Bifoldable t, Monad m) => (a -> b -> m a) -> (a -> c -> m a) -> a -> t b c -> m a bifoldlM f g z0 xs = bifoldr f' g' return xs z0 where f' x k z = f z x >>= k g' x k z = g z x >>= k {-# INLINE bifoldlM #-} +-- | As 'Data.Bitraversable.bitraverse', but ignores the results of the+-- functions, merely performing the "actions". bitraverse_ :: (Bifoldable t, Applicative f) => (a -> f c) -> (b -> f d) -> t a b -> f () bitraverse_ f g = bifoldr ((*>) . f) ((*>) . g) (pure ()) {-# INLINE bitraverse_ #-} +-- | As 'bitraverse_', but with the structure as the primary argument. bifor_ :: (Bifoldable t, Applicative f) => t a b -> (a -> f c) -> (b -> f d) -> f () bifor_ t f g = bitraverse_ f g t {-# INLINE bifor_ #-} +-- | As 'Data.Bitraversable.bimapM', but ignores the results of the functions,+-- merely performing+-- the "actions". bimapM_:: (Bifoldable t, Monad m) => (a -> m c) -> (b -> m d) -> t a b -> m () bimapM_ f g = bifoldr ((>>) . f) ((>>) . g) (return ()) {-# INLINE bimapM_ #-} +-- | As 'bimapM_', but with the structure as the primary argument. biforM_ :: (Bifoldable t, Monad m) => t a b -> (a -> m c) -> (b -> m d) -> m () biforM_ t f g = bimapM_ f g t {-# INLINE biforM_ #-} +-- | As 'Data.Bitraversable.bisequenceA', but ignores the results of the actions. bisequenceA_ :: (Bifoldable t, Applicative f) => t (f a) (f b) -> f () bisequenceA_ = bifoldr (*>) (*>) (pure ()) {-# INLINE bisequenceA_ #-} +-- | As 'Data.Bitraversable.bisequence', but ignores the results of the actions. bisequence_ :: (Bifoldable t, Monad m) => t (m a) (m b) -> m () bisequence_ = bifoldr (>>) (>>) (return ()) {-# INLINE bisequence_ #-} +-- | Collects the list of elements of a structure in order. biList :: Bifoldable t => t a a -> [a] biList = bifoldr (:) (:) [] {-# INLINE biList #-} +-- | Reduces a structure of lists to the concatenation of those lists. biconcat :: Bifoldable t => t [a] [a] -> [a] biconcat = bifold {-# INLINE biconcat #-} +-- | Given a means of mapping the elements of a structure to lists, computes the+-- concatenation of all such lists in order. biconcatMap :: Bifoldable t => (a -> [c]) -> (b -> [c]) -> t a b -> [c] biconcatMap = bifoldMap {-# INLINE biconcatMap #-} +-- | Determines whether any element of the structure satisfies the appropriate+-- predicate. biany :: Bifoldable t => (a -> Bool) -> (b -> Bool) -> t a b -> Bool biany p q = getAny . bifoldMap (Any . p) (Any . q) {-# INLINE biany #-} +-- | Determines whether all elements of the structure satisfy the appropriate+-- predicate. biall :: Bifoldable t => (a -> Bool) -> (b -> Bool) -> t a b -> Bool biall p q = getAll . bifoldMap (All . p) (All . q) {-# INLINE biall #-}
src/Data/Bitraversable.hs view
@@ -25,19 +25,123 @@ import Data.Monoid import Data.Tagged +-- | Minimal complete definition either 'bitraverse' or 'bisequenceA'.++-- | 'Bitraversable' identifies bifunctorial data structures whose elements can+-- be traversed in order, performing 'Applicative' or 'Monad' actions at each+-- element, and collecting a result structure with the same shape.+--+-- A definition of 'traverse' must satisfy the following laws:+--+-- [/naturality/]+-- @'bitraverse' (t . f) (t . g) ≡ t . 'bitraverse' f g@+-- for every applicative transformation @t@+--+-- [/identity/]+-- @'bitraverse' 'Identity' 'Identity' ≡ 'Identity'@+--+-- [/composition/]+-- @'Compose' . 'fmap' ('bitraverse' g1 g2) . 'bitraverse' f1 f2+-- ≡ 'traverse' ('Compose' . 'fmap' g1 . f1) ('Compose' . 'fmap' g2 . f2)@+--+-- A definition of 'bisequenceA' must satisfy the following laws:+--+-- [/naturality/]+-- @'bisequenceA' . 'bimap' t t ≡ t . 'bisequenceA'@+-- for every applicative transformation @t@+--+-- [/identity/]+-- @'bisequenceA' . 'bimap' 'Identity' 'Identity' ≡ 'Identity'@+--+-- [/composition/]+-- @'bisequenceA' . 'bimap' 'Compose' 'Compose'+-- ≡ 'Compose' . 'fmap' 'bisequenceA' . 'bisequenceA'@+--+-- where an /applicative transformation/ is a function+--+-- @t :: ('Applicative' f, 'Applicative' g) => f a -> g a@+--+-- preserving the 'Applicative' operations:+--+-- @+-- t ('pure' x) = 'pure' x+-- t (f '<*>' x) = t f '<*>' t x+-- @+--+-- and the identity functor 'Identity' and composition functors 'Compose' are+-- defined as+--+-- > newtype Identity a = Identity { runIdentity :: a }+-- >+-- > instance Functor Identity where+-- > fmap f (Identity x) = Identity (f x)+-- >+-- > instance Applicative Identity where+-- > pure = Identity+-- > Identity f <*> Identity x = Identity (f x)+-- >+-- > newtype Compose f g a = Compose (f (g a))+-- >+-- > instance (Functor f, Functor g) => Functor (Compose f g) where+-- > fmap f (Compose x) = Compose (fmap (fmap f) x)+-- >+-- > instance (Applicative f, Applicative g) => Applicative (Compose f g) where+-- > pure = Compose . pure . pure+-- > Compose f <*> Compose x = Compose ((<*>) <$> f <*> x)+--+-- Some simple examples are 'Either' and '(,)':+--+-- > instance Bitraversable Either where+-- > bitraverse f _ (Left x) = Left <$> f x+-- > bitraverse _ g (Right y) = Right <$> g y+-- >+-- > instance Bitraversable (,) where+-- > bitraverse f g (x, y) = (,) <$> f x <*> g y+--+-- 'Bitraversable' relates to its superclasses in the following ways:+--+-- @+-- 'bimap' f g ≡ 'runIdentity' . 'bitraverse' ('Identity' . f) ('Identity' . g)+-- 'bifoldMap' f g = 'getConst' . 'bitraverse' ('Const' . f) ('Const' . g)+-- @+--+-- These are available as 'bimapDefault' and 'bifoldMapDefault' respectively. class (Bifunctor t, Bifoldable t) => Bitraversable t where+ -- | Evaluates the relevant functions at each element in the structure, running+ -- the action, and builds a new structure with the same shape, using the+ -- elements produced from sequencing the actions.+ --+ -- @'bitraverse' f g ≡ 'bisequenceA' . 'bimap' f g@ bitraverse :: Applicative f => (a -> f c) -> (b -> f d) -> t a b -> f (t c d) bitraverse f g = bisequenceA . bimap f g {-# INLINE bitraverse #-} + -- | Sequences all the actions in a structure, building a new structure with the+ -- same shape using the results of the actions.+ --+ -- @'bisequenceA' ≡ 'bitraverse' 'id' 'id'@ bisequenceA :: Applicative f => t (f a) (f b) -> f (t a b) bisequenceA = bitraverse id id {-# INLINE bisequenceA #-} + -- | As 'bitraverse', but uses evidence that @m@ is a 'Monad' rather than an+ -- 'Applicative'.+ --+ -- @+ -- 'bimapM' f g ≡ 'bisequence' . 'bimap' f g+ -- 'bimapM' f g ≡ 'unwrapMonad' . 'bitraverse' ('WrapMonad' . f) ('WrapMonad' . g)+ -- @ bimapM :: Monad m => (a -> m c) -> (b -> m d) -> t a b -> m (t c d) bimapM f g = unwrapMonad . bitraverse (WrapMonad . f) (WrapMonad . g) {-# INLINE bimapM #-} + -- | As 'bisequenceA', but uses evidence that @m@ is a 'Monad' rather than an+ -- 'Applicative'.+ --+ -- @+ -- 'bisequence' ≡ 'bimapM' 'id' 'id'+ -- 'bisequence' ≡ 'unwrapMonad' . 'bisequenceA' . 'bimap' 'WrapMonad' 'WrapMonad'+ -- @ bisequence :: Monad m => t (m a) (m b) -> m (t a b) bisequence = bimapM id id {-# INLINE bisequence #-}@@ -71,10 +175,12 @@ bitraverse _ g (Tagged b) = Tagged <$> g b {-# INLINE bitraverse #-} +-- | 'bifor' is 'bitraverse' with the structure as the first argument. bifor :: (Bitraversable t, Applicative f) => t a b -> (a -> f c) -> (b -> f d) -> f (t c d) bifor t f g = bitraverse f g t {-# INLINE bifor #-} +-- | 'biforM' is 'bimapM' with the structure as the first argument. biforM :: (Bitraversable t, Monad m) => t a b -> (a -> m c) -> (b -> m d) -> m (t c d) biforM t f g = bimapM f g t {-# INLINE biforM #-}@@ -96,6 +202,8 @@ in (s'', f v) {-# INLINE (<*>) #-} +-- | Traverses a structure from left to right, threading a state of type @a@+-- and using the given actions to compute new elements for the structure. bimapAccumL :: Bitraversable t => (a -> b -> (a, c)) -> (a -> d -> (a, e)) -> a -> t b d -> (a, t c e) bimapAccumL f g s t = runStateL (bitraverse (StateL . flip f) (StateL . flip g) t) s {-# INLINE bimapAccumL #-}@@ -117,6 +225,8 @@ in (s'', f v) {-# INLINE (<*>) #-} +-- | Traverses a structure from right to left, threading a state of type @a@+-- and using the given actions to compute new elements for the structure. bimapAccumR :: Bitraversable t => (a -> b -> (a, c)) -> (a -> d -> (a, e)) -> a -> t b d -> (a, t c e) bimapAccumR f g s t = runStateR (bitraverse (StateR . flip f) (StateR . flip g) t) s {-# INLINE bimapAccumR #-}@@ -133,10 +243,12 @@ Id f <*> Id x = Id (f x) {-# INLINE (<*>) #-} +-- | A default definition of 'bimap' in terms of the 'Bitraversable' operations. bimapDefault :: Bitraversable t => (a -> b) -> (c -> d) -> t a c -> t b d bimapDefault f g = getId . bitraverse (Id . f) (Id . g) {-# INLINE bimapDefault #-} +-- | A default definition of 'bifoldMap' in terms of the 'Bitraversable' operations. bifoldMapDefault :: (Bitraversable t, Monoid m) => (a -> m) -> (b -> m) -> t a b -> m bifoldMapDefault f g = getConst . bitraverse (Const . f) (Const . g) {-# INLINE bifoldMapDefault #-}