-- |
-- Module : Basement.Mappable
-- License : BSD-style
-- Maintainer : Nicolas Di Prima
-- Stability : experimental
-- Portability : portable
--
-- Class of collection that can be traversed from left to right,
-- performing an action on each element.
--
module Foundation.Collection.Mappable
( Mappable(..)
, sequence_
, traverse_
, mapM_
, forM
, forM_
) where
import Basement.Compat.Base
import qualified Data.Traversable
import Basement.BoxedArray (Array)
-- | Functors representing data structures that can be traversed from
-- left to right.
--
-- Mostly like base's `Traversable` but applied to collections only.
--
class Functor collection => Mappable collection where
{-# MINIMAL traverse | sequenceA #-}
-- | Map each element of a structure to an action, evaluate these actions
-- from left to right, and collect the results. For a version that ignores
-- the results see 'Foundation.Collection.traverse_'.
traverse :: Applicative f => (a -> f b)
-> collection a
-> f (collection b)
traverse f = sequenceA . fmap f
-- | Evaluate each actions of the given collections, from left to right,
-- and collect the results. For a version that ignores the results, see
-- `Foundation.Collection.sequenceA_`
sequenceA :: Applicative f => collection (f a)
-> f (collection a)
sequenceA = traverse id
-- | Map each element of the collection to an action, evaluate these actions
-- from left to right, and collect the results. For a version that ignores
-- the results see 'Foundation.Collection.mapM_'.
mapM :: (Applicative m, Monad m) => (a -> m b) -> collection a -> m (collection b)
mapM = traverse
-- | Evaluate each actions of the given collections, from left to right,
-- and collect the results. For a version that ignores the results, see
-- `Foundation.Collection.sequence_`
sequence :: (Applicative m, Monad m) => collection (m a) -> m (collection a)
sequence = sequenceA
-- | Map each element of a collection to an action, evaluate these
-- actions from left to right, and ignore the results. For a version
-- that doesn't ignore the results see 'Foundation.Collection.traverse`
traverse_ :: (Mappable col, Applicative f) => (a -> f b) -> col a -> f ()
traverse_ f col = traverse f col *> pure ()
-- | Evaluate each action in the collection from left to right, and
-- ignore the results. For a version that doesn't ignore the results
-- see 'Foundation.Collection.sequenceA'.
--sequenceA_ :: (Mappable col, Applicative f) => col (f a) -> f ()
--sequenceA_ col = sequenceA col *> pure ()
-- | Map each element of a collection to a monadic action, evaluate
-- these actions from left to right, and ignore the results. For a
-- version that doesn't ignore the results see
-- 'Foundation.Collection.mapM'.
mapM_ :: (Mappable col, Applicative m, Monad m) => (a -> m b) -> col a -> m ()
mapM_ f c = mapM f c *> return ()
-- | Evaluate each monadic action in the collection from left to right,
-- and ignore the results. For a version that doesn't ignore the
-- results see 'Foundation.Collection.sequence'.
sequence_ :: (Mappable col, Applicative m, Monad m) => col (m a) -> m ()
sequence_ c = sequence c *> return ()
-- | 'forM' is 'mapM' with its arguments flipped. For a version that
-- ignores the results see 'Foundation.Collection.forM_'.
forM :: (Mappable col, Applicative m, Monad m) => col a -> (a -> m b) -> m (col b)
forM = flip mapM
-- | 'forM_' is 'mapM_' with its arguments flipped. For a version that
-- doesn't ignore the results see 'Foundation.Collection.forM'.
forM_ :: (Mappable col, Applicative m, Monad m) => col a -> (a -> m b) -> m ()
forM_ = flip mapM_
----------------------------
-- Foldable instances
----------------------------
instance Mappable [] where
{-# INLINE traverse #-}
traverse = Data.Traversable.traverse
instance Mappable Array where
-- | TODO: to optimise
traverse f arr = fromList <$> traverse f (toList arr)