content: {-# LANGUAGE Trustworthy #-}
  {-# LANGUAGE NoImplicitPrelude #-}
  
  -----------------------------------------------------------------------------
  -- |
  -- Module      :  Control.Monad
  -- Copyright   :  (c) The University of Glasgow 2001
  -- License     :  BSD-style (see the file libraries/base/LICENSE)
  --
  -- Maintainer  :  libraries@haskell.org
  -- Stability   :  provisional
  -- Portability :  portable
  --
  -- The 'Functor', 'Monad' and 'MonadPlus' classes,
  -- with some useful operations on monads.
  
  module Control.Monad
      (
      -- * Functor and monad classes
  
        Functor(fmap)
      , Monad((>>=), (>>), return, fail)
      , MonadPlus(mzero, mplus)
      -- * Functions
  
      -- ** Naming conventions
      -- $naming
  
      -- ** Basic @Monad@ functions
  
      , mapM
      , mapM_
      , forM
      , forM_
      , sequence
      , sequence_
      , (=<<)
      , (>=>)
      , (<=<)
      , forever
      , void
  
      -- ** Generalisations of list functions
  
      , join
      , msum
      , mfilter
      , filterM
      , mapAndUnzipM
      , zipWithM
      , zipWithM_
      , foldM
      , foldM_
      , replicateM
      , replicateM_
  
      -- ** Conditional execution of monadic expressions
  
      , guard
      , when
      , unless
  
      -- ** Monadic lifting operators
  
      , liftM
      , liftM2
      , liftM3
      , liftM4
      , liftM5
  
      , ap
  
      -- ** Strict monadic functions
  
      , (<$!>)
      ) where
  
  import Data.Foldable ( Foldable, sequence_, msum, mapM_, foldlM, forM_ )
  import Data.Functor ( void )
  import Data.Traversable ( forM, mapM, sequence )
  
  import GHC.Base hiding ( mapM, sequence )
  import GHC.List ( zipWith, unzip, replicate )
  
  -- -----------------------------------------------------------------------------
  -- Functions mandated by the Prelude
  
  -- | @'guard' b@ is @'pure' ()@ if @b@ is 'True',
  -- and 'empty' if @b@ is 'False'.
  guard           :: (Alternative f) => Bool -> f ()
  guard True      =  pure ()
  guard False     =  empty
  
  -- | This generalizes the list-based 'filter' function.
  
  {-# INLINE filterM #-}
  filterM          :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
  filterM p        = foldr go (return [])
    where
      go x r = do
        flg <- p x
        ys <- r
        return (if flg then x:ys else ys)
  
  infixr 1 <=<, >=>
  
  -- | Left-to-right Kleisli composition of monads.
  (>=>)       :: Monad m => (a -> m b) -> (b -> m c) -> (a -> m c)
  f >=> g     = \x -> f x >>= g
  
  -- | Right-to-left Kleisli composition of monads. @('>=>')@, with the arguments flipped
  (<=<)       :: Monad m => (b -> m c) -> (a -> m b) -> (a -> m c)
  (<=<)       = flip (>=>)
  
  -- | @'forever' act@ repeats the action infinitely.
  forever     :: (Monad m) => m a -> m b
  {-# INLINE forever #-}
  forever a   = let a' = a >> a' in a'
  -- Use explicit sharing here, as it is prevents a space leak regardless of
  -- optimizations.
  
  -- -----------------------------------------------------------------------------
  -- Other monad functions
  
  -- | The 'mapAndUnzipM' function maps its first argument over a list, returning
  -- the result as a pair of lists. This function is mainly used with complicated
  -- data structures or a state-transforming monad.
  mapAndUnzipM      :: (Monad m) => (a -> m (b,c)) -> [a] -> m ([b], [c])
  {-# INLINE mapAndUnzipM #-}
  mapAndUnzipM f xs =  sequence (map f xs) >>= return . unzip
  
  -- | The 'zipWithM' function generalizes 'zipWith' to arbitrary monads.
  zipWithM          :: (Monad m) => (a -> b -> m c) -> [a] -> [b] -> m [c]
  {-# INLINE zipWithM #-}
  zipWithM f xs ys  =  sequence (zipWith f xs ys)
  
  -- | 'zipWithM_' is the extension of 'zipWithM' which ignores the final result.
  zipWithM_         :: (Monad m) => (a -> b -> m c) -> [a] -> [b] -> m ()
  {-# INLINE zipWithM_ #-}
  zipWithM_ f xs ys =  sequence_ (zipWith f xs ys)
  
  {- | The 'foldM' function is analogous to 'foldl', except that its result is
  encapsulated in a monad. Note that 'foldM' works from left-to-right over
  the list arguments. This could be an issue where @('>>')@ and the `folded
  function' are not commutative.
  
  
  >       foldM f a1 [x1, x2, ..., xm]
  
  ==
  
  >       do
  >         a2 <- f a1 x1
  >         a3 <- f a2 x2
  >         ...
  >         f am xm
  
  If right-to-left evaluation is required, the input list should be reversed.
  
  Note: 'foldM' is the same as 'foldlM'
  -}
  
  foldM          :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m b
  {-# INLINEABLE foldM #-}
  {-# SPECIALISE foldM :: (a -> b -> IO a) -> a -> [b] -> IO a #-}
  {-# SPECIALISE foldM :: (a -> b -> Maybe a) -> a -> [b] -> Maybe a #-}
  foldM          = foldlM
  
  -- | Like 'foldM', but discards the result.
  foldM_         :: (Foldable t, Monad m) => (b -> a -> m b) -> b -> t a -> m ()
  {-# INLINEABLE foldM_ #-}
  {-# SPECIALISE foldM_ :: (a -> b -> IO a) -> a -> [b] -> IO () #-}
  {-# SPECIALISE foldM_ :: (a -> b -> Maybe a) -> a -> [b] -> Maybe () #-}
  foldM_ f a xs  = foldlM f a xs >> return ()
  
  -- | @'replicateM' n act@ performs the action @n@ times,
  -- gathering the results.
  replicateM        :: (Monad m) => Int -> m a -> m [a]
  {-# INLINEABLE replicateM #-}
  {-# SPECIALISE replicateM :: Int -> IO a -> IO [a] #-}
  {-# SPECIALISE replicateM :: Int -> Maybe a -> Maybe [a] #-}
  replicateM n x    = sequence (replicate n x)
  
  -- | Like 'replicateM', but discards the result.
  replicateM_       :: (Monad m) => Int -> m a -> m ()
  {-# INLINEABLE replicateM_ #-}
  {-# SPECIALISE replicateM_ :: Int -> IO a -> IO () #-}
  {-# SPECIALISE replicateM_ :: Int -> Maybe a -> Maybe () #-}
  replicateM_ n x   = sequence_ (replicate n x)
  
  -- | The reverse of 'when'.
  unless            :: (Applicative f) => Bool -> f () -> f ()
  {-# INLINEABLE unless #-}
  {-# SPECIALISE unless :: Bool -> IO () -> IO () #-}
  {-# SPECIALISE unless :: Bool -> Maybe () -> Maybe () #-}
  unless p s        =  if p then pure () else s
  
  infixl 4 <$!>
  
  -- | Strict version of 'Data.Functor.<$>'.
  --
  -- @since 4.8.0.0
  (<$!>) :: Monad m => (a -> b) -> m a -> m b
  {-# INLINE (<$!>) #-}
  f <$!> m = do
    x <- m
    let z = f x
    z `seq` return z
  
  
  -- -----------------------------------------------------------------------------
  -- Other MonadPlus functions
  
  -- | Direct 'MonadPlus' equivalent of 'filter'
  -- @'filter'@ = @(mfilter:: (a -> Bool) -> [a] -> [a]@
  -- applicable to any 'MonadPlus', for example
  -- @mfilter odd (Just 1) == Just 1@
  -- @mfilter odd (Just 2) == Nothing@
  
  mfilter :: (MonadPlus m) => (a -> Bool) -> m a -> m a
  {-# INLINEABLE mfilter #-}
  mfilter p ma = do
    a <- ma
    if p a then return a else mzero
  
  {- $naming
  
  The functions in this library use the following naming conventions:
  
  * A postfix \'@M@\' always stands for a function in the Kleisli category:
    The monad type constructor @m@ is added to function results
    (modulo currying) and nowhere else.  So, for example,
  
  >  filter  ::              (a ->   Bool) -> [a] ->   [a]
  >  filterM :: (Monad m) => (a -> m Bool) -> [a] -> m [a]
  
  * A postfix \'@_@\' changes the result type from @(m a)@ to @(m ())@.
    Thus, for example:
  
  >  sequence  :: Monad m => [m a] -> m [a]
  >  sequence_ :: Monad m => [m a] -> m ()
  
  * A prefix \'@m@\' generalizes an existing function to a monadic form.
    Thus, for example:
  
  >  sum  :: Num a       => [a]   -> a
  >  msum :: MonadPlus m => [m a] -> m a
  
  -}
  