content: {-# LANGUAGE Safe #-}
  
  {- |
  Module                  : Relude.Monad.Maybe
  Copyright               : (c) 2016 Stephen Diehl
                            (c) 2016-2018 Serokell
                            (c) 2018-2023 Kowainik
  SPDX-License-Identifier : MIT
  Maintainer              : Kowainik <xrom.xkov@gmail.com>
  Stability               : Stable
  Portability             : Portable
  
  Utility functions to work with 'Relude.Monad.Reexport.Maybe' data type as monad.
  -}
  
  module Relude.Monad.Maybe
      ( -- * Combinators
        (?:)
      , whenJust
      , whenJustM
      , whenNothing
      , whenNothing_
        -- * Monadic combinators
      , whenNothingM
      , whenNothingM_
      , mapMaybeM
      ) where
  
  import Relude.Applicative (Applicative, pass, pure)
  import Relude.Foldable.Reexport (mapM)
  import Relude.Function ((.))
  import Relude.Functor.Reexport (fmap)
  import Relude.Monad.Reexport (Maybe (..), Monad (..), catMaybes, fromMaybe)
  
  
  -- $setup
  -- >>> import Relude
  
  {- | Similar to 'fromMaybe' but with flipped arguments.
  
  >>> readMaybe "True" ?: False
  True
  
  >>> readMaybe "Tru" ?: False
  False
  -}
  infixr 0 ?:
  (?:) :: Maybe a -> a -> a
  mA ?: b = fromMaybe b mA
  {-# INLINE (?:) #-}
  
  {- | Specialized version of 'Relude.Foldable.Reexport.for_' for 'Maybe'. It's used for code readability.
  
  Also helps to avoid space leaks:
  <http://www.snoyman.com/blog/2017/01/foldable-mapm-maybe-and-recursive-functions Foldable.mapM_ space leak>.
  
  >>> whenJust Nothing $ \b -> print (not b)
  >>> whenJust (Just True) $ \b -> print (not b)
  False
  -}
  whenJust :: Applicative f => Maybe a -> (a -> f ()) -> f ()
  whenJust (Just x) f = f x
  whenJust Nothing _  = pass
  {-# INLINE whenJust #-}
  
  {- | Monadic version of 'whenJust'.
  
  >>> whenJustM (pure Nothing) $ \b -> print (not b)
  >>> whenJustM (pure $ Just True) $ \b -> print (not b)
  False
  -}
  whenJustM :: Monad m => m (Maybe a) -> (a -> m ()) -> m ()
  whenJustM mm f = mm >>= \m -> whenJust m f
  {-# INLINE whenJustM #-}
  
  {- | Performs default 'Applicative' action if 'Nothing' is given.
  Otherwise returns content of 'Just' pured to 'Applicative'.
  
  >>> whenNothing Nothing [True, False]
  [True,False]
  >>> whenNothing (Just True) [True, False]
  [True]
  -}
  whenNothing :: Applicative f => Maybe a -> f a -> f a
  whenNothing (Just x) _ = pure x
  whenNothing Nothing  m = m
  {-# INLINE whenNothing #-}
  
  {- | Performs default 'Applicative' action if 'Nothing' is given.
  Do nothing for 'Just'. Convenient for discarding 'Just' content.
  
  >>> whenNothing_ Nothing $ putTextLn "Nothing!"
  Nothing!
  >>> whenNothing_ (Just True) $ putTextLn "Nothing!"
  -}
  whenNothing_ :: Applicative f => Maybe a -> f () -> f ()
  whenNothing_ Nothing m = m
  whenNothing_ _       _ = pass
  {-# INLINE whenNothing_ #-}
  
  {- | Monadic version of 'whenNothing'.
  
  >>> whenNothingM (pure $ Just True) $ True <$ putTextLn "Is Just!"
  True
  >>> whenNothingM (pure Nothing) $ False <$ putTextLn "Is Nothing!"
  Is Nothing!
  False
  -}
  whenNothingM :: Monad m => m (Maybe a) -> m a -> m a
  whenNothingM mm action = mm >>= \m -> whenNothing m action
  {-# INLINE whenNothingM #-}
  
  {- | Monadic version of 'whenNothing_'.
  
  >>> whenNothingM_ (pure $ Just True) $ putTextLn "Is Just!"
  >>> whenNothingM_ (pure Nothing) $ putTextLn "Is Nothing!"
  Is Nothing!
  -}
  whenNothingM_ :: Monad m => m (Maybe a) -> m () -> m ()
  whenNothingM_ mm action = mm >>= \m -> whenNothing_ m action
  {-# INLINE whenNothingM_ #-}
  
  
  {- | The monadic version of the 'Data.Maybe.mapMaybe' function.
  
  >>> :{
  evenInHalf :: Int -> IO (Maybe Int)
  evenInHalf n
      | even n = pure $ Just $ n `div` 2
      | otherwise = pure Nothing
  :}
  
  >>> mapMaybeM evenInHalf [1..10]
  [1,2,3,4,5]
  
  @since 0.6.0.0
  -}
  mapMaybeM :: (Monad m) => (a -> m (Maybe b)) -> [a] -> m [b]
  mapMaybeM f = fmap catMaybes . mapM f
  {-# INLINE mapMaybeM #-}
  