{-# LANGUAGE NoImplicitPrelude, UnicodeSyntax #-}

{-|
Module     : PreludePlus.Prelude
Copyright  : 2018 Joshua Booth
License    : BSD3 (see the file LICENSE)
Maintainer : Joshua Booth <joshua.n.booth@gmail.com>

Generalizes List functions to MonadPlus etc. and replaces partials and group(By) with NonEmpty equivalents.
-}
module PreludePlus (module Import, (++), concat, concatMap, catMaybes, filter, fromList, mapMaybe, map, mapM, mapM_, sequence, sequence_) where

import Prelude             as Import hiding ((!!), (++), concat, concatMap, filter, head, last, map, mapM, mapM_, sequence, sequence_, tail, init)
import Control.Monad       as Import hiding (mapM, mapM_, sequence, sequence_)
import Data.Foldable       as Import hiding (concat, concatMap, mapM, mapM_, sequence, sequence_)
import Data.List           as Import hiding ((!!), (++), concat, concatMap, filter, group, groupBy, head, last, map, tail, init, insert)
import Data.List.NonEmpty  as Import (NonEmpty(..), (!!), group, groupBy, head, last, tail, init)
import Data.Maybe          as Import hiding (catMaybes, mapMaybe)

import Control.Applicative (Alternative)
--import Control.Monad       (MonadPlus, mfilter, mzero)
import Data.Monoid         ((<>))

-- | '<>'
(++)  Semigroup a => a  a  a
(++) = (<>)

-- | 'asum'
concat  (Foldable t, Alternative f) => t (f a)  f a
concat = asum

-- | 'asum' . 'fmap'
concatMap  (Alternative f, Foldable t, Functor t) => (a  f b)  t a  f b
concatMap f = asum . fmap f

-- | Reduces a collection of Maybes to its Just values.
catMaybes  MonadPlus m => m (Maybe a)  m a
catMaybes xs = do
    x  xs
    case x of
      Just a   return a
      Nothing  mzero

-- | 'mfilter'
filter   MonadPlus m => (a  Bool)  m a  m a
filter = mfilter

-- | Transforms a list into any 'MonadPlus' using 'asum'.
fromList  MonadPlus m => [a]  m a
fromList = asum . fmap return

-- | 'fmap'
map  Functor f => (a  b)  f a  f b
map = fmap

-- | 'traverse'
mapM  (Applicative f, Traversable t) => (a  f b)  t a  f (t b)
mapM = traverse

-- | 'traverse_'
mapM_  (Foldable t, Applicative f) => (a  f b)  t a  f ()
mapM_ = traverse_

-- | 'catMaybes' . 'fmap'
mapMaybe  MonadPlus m => (a  Maybe b)  m a  m b
mapMaybe f = catMaybes . fmap f

-- | 'sequenceA'
sequence  (Traversable t, Applicative f) => t (f a)  f (t a)
sequence = sequenceA

-- | 'sequenceA_'
sequence_  (Foldable t, Applicative f) => t (f a)  f ()
sequence_ = sequenceA_