    -- |
    -- Module      : Basement.Mappable
    -- License     : BSD-style
    -- Maintainer  : Nicolas Di Prima <nicolas@primetype.co.uk>
    -- 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 :: a -> f b
    f = collection (f b) -> f (collection b)
    forall (collection :: * -> *) (f :: * -> *) a.
    (Mappable collection, Applicative f) =>
    collection (f a) -> f (collection a)
    sequenceA (collection (f b) -> f (collection b))
    -> (collection a -> collection (f b))
    -> collection a
    -> f (collection b)
    forall k (cat :: k -> k -> *) (b :: k) (c :: k) (a :: k).
    Category cat =>
    cat b c -> cat a b -> cat a c
    . (a -> f b) -> collection a -> collection (f b)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    fmap a -> f b
    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 = (f a -> f a) -> collection (f a) -> f (collection a)
    forall (collection :: * -> *) (f :: * -> *) a b.
    (Mappable collection, Applicative f) =>
    (a -> f b) -> collection a -> f (collection b)
    traverse f a -> f a
    forall k (cat :: k -> k -> *) (a :: k). Category cat => cat a a
    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 = (a -> m b) -> collection a -> m (collection b)
    forall (collection :: * -> *) (f :: * -> *) a b.
    (Mappable collection, Applicative f) =>
    (a -> f b) -> collection a -> f (collection b)
    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 = collection (m a) -> m (collection a)
    forall (collection :: * -> *) (f :: * -> *) a.
    (Mappable collection, Applicative f) =>
    collection (f a) -> f (collection a)
    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_ :: (a -> f b) -> col a -> f ()
    traverse_ f :: a -> f b
    f col :: col a
    col = (a -> f b) -> col a -> f (col b)
    forall (collection :: * -> *) (f :: * -> *) a b.
    (Mappable collection, Applicative f) =>
    (a -> f b) -> collection a -> f (collection b)
    traverse a -> f b
    f col a
    col f (col b) -> f () -> f ()
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> () -> f ()
    forall (f :: * -> *) a. Applicative f => a -> f a
    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_ :: (a -> m b) -> col a -> m ()
    mapM_ f :: a -> m b
    f c :: col a
    c = (a -> m b) -> col a -> m (col b)
    forall (collection :: * -> *) (m :: * -> *) a b.
    (Mappable collection, Applicative m, Monad m) =>
    (a -> m b) -> collection a -> m (collection b)
    mapM a -> m b
    f col a
    c m (col b) -> m () -> m ()
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> () -> m ()
    forall (m :: * -> *) a. Monad m => a -> m a
    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_ :: col (m a) -> m ()
    sequence_ c :: col (m a)
    c = col (m a) -> m (col a)
    forall (collection :: * -> *) (m :: * -> *) a.
    (Mappable collection, Applicative m, Monad m) =>
    collection (m a) -> m (collection a)
    sequence col (m a)
    c m (col a) -> m () -> m ()
    forall (f :: * -> *) a b. Applicative f => f a -> f b -> f b
    *> () -> m ()
    forall (m :: * -> *) a. Monad m => a -> m a
    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 :: col a -> (a -> m b) -> m (col b)
    forM = ((a -> m b) -> col a -> m (col b))
    -> col a -> (a -> m b) -> m (col b)
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (a -> m b) -> col a -> m (col b)
    forall (collection :: * -> *) (m :: * -> *) a b.
    (Mappable collection, Applicative m, Monad m) =>
    (a -> m b) -> collection a -> m (collection b)
    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_ :: col a -> (a -> m b) -> m ()
    forM_ = ((a -> m b) -> col a -> m ()) -> col a -> (a -> m b) -> m ()
    forall a b c. (a -> b -> c) -> b -> a -> c
    flip (a -> m b) -> col a -> m ()
    forall (col :: * -> *) (m :: * -> *) a b.
    (Mappable col, Applicative m, Monad m) =>
    (a -> m b) -> col a -> m ()
    mapM_

    ----------------------------
    -- Foldable instances
    ----------------------------

    instance Mappable [] where
        {-# INLINE traverse #-}
        traverse :: (a -> f b) -> [a] -> f [b]
    traverse = (a -> f b) -> [a] -> f [b]
    forall (t :: * -> *) (f :: * -> *) a b.
    (Traversable t, Applicative f) =>
    (a -> f b) -> t a -> f (t b)
    Data.Traversable.traverse

    instance Mappable Array where
        -- | TODO: to optimise
        traverse :: (a -> f b) -> Array a -> f (Array b)
    traverse f :: a -> f b
    f arr :: Array a
    arr = [b] -> Array b
    forall l. IsList l => [Item l] -> l
    fromList ([b] -> Array b) -> f [b] -> f (Array b)
    forall (f :: * -> *) a b. Functor f => (a -> b) -> f a -> f b
    <$> (a -> f b) -> [a] -> f [b]
    forall (collection :: * -> *) (f :: * -> *) a b.
    (Mappable collection, Applicative f) =>
    (a -> f b) -> collection a -> f (collection b)
    traverse a -> f b
    f (Array a -> [Item (Array a)]
    forall l. IsList l => l -> [Item l]
    toList Array a
    arr)