{-# LANGUAGE Safe #-}

-- | Utility functions to work with 'Data.Maybe' data type as monad.

module Universum.Monad.Maybe
       ( (?:)
       , whenJust
       , whenJustM
       , whenNothing
       , whenNothing_
       , whenNothingM
       , whenNothingM_
       ) where

import Universum.Applicative (Applicative, pass, pure)
import Universum.Monad.Reexport (Maybe (..), Monad (..), fromMaybe)

-- $setup
-- >>> import Universum.Bool (Bool (..), not)
-- >>> import Universum.Function (($))
-- >>> import Universum.Print (putTextLn, print)
-- >>> import Universum.String (readMaybe)

{- | Similar to 'fromMaybe' but with flipped arguments.

>>> readMaybe "True" ?: False
True

>>> readMaybe "Tru" ?: False
False

-}
infixr 0 ?:
(?:) :: Maybe a -> a -> a
Maybe a
mA ?: :: forall a. Maybe a -> a -> a
?: a
b = forall a. a -> Maybe a -> a
fromMaybe a
b Maybe a
mA
{-# INLINE (?:) #-}

{- | Specialized version of '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 :: forall (f :: * -> *) a.
Applicative f =>
Maybe a -> (a -> f ()) -> f ()
whenJust (Just a
x) a -> f ()
f = a -> f ()
f a
x
whenJust Maybe a
Nothing a -> f ()
_  = forall (f :: * -> *). Applicative f => f ()
pass
{-# INLINE whenJust #-}

-- | Monadic version of 'whenJust'.
whenJustM :: Monad m => m (Maybe a) -> (a -> m ()) -> m ()
whenJustM :: forall (m :: * -> *) a.
Monad m =>
m (Maybe a) -> (a -> m ()) -> m ()
whenJustM m (Maybe a)
mm a -> m ()
f = m (Maybe a)
mm forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Maybe a
m -> forall (f :: * -> *) a.
Applicative f =>
Maybe a -> (a -> f ()) -> f ()
whenJust Maybe a
m a -> 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 :: forall (f :: * -> *) a. Applicative f => Maybe a -> f a -> f a
whenNothing (Just a
x) f a
_ = forall (f :: * -> *) a. Applicative f => a -> f a
pure a
x
whenNothing Maybe a
Nothing  f a
m = f a
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_ :: forall (f :: * -> *) a. Applicative f => Maybe a -> f () -> f ()
whenNothing_ Maybe a
Nothing f ()
m = f ()
m
whenNothing_ Maybe a
_       f ()
_ = forall (f :: * -> *). Applicative f => f ()
pass
{-# INLINE whenNothing_ #-}

-- | Monadic version of 'whenNothing'.
whenNothingM :: Monad m => m (Maybe a) -> m a -> m a
whenNothingM :: forall (m :: * -> *) a. Monad m => m (Maybe a) -> m a -> m a
whenNothingM m (Maybe a)
mm m a
action = m (Maybe a)
mm forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Maybe a
m -> forall (f :: * -> *) a. Applicative f => Maybe a -> f a -> f a
whenNothing Maybe a
m m a
action
{-# INLINE whenNothingM #-}

-- | Monadic version of 'whenNothingM_'.
whenNothingM_ :: Monad m => m (Maybe a) -> m () -> m ()
whenNothingM_ :: forall (m :: * -> *) a. Monad m => m (Maybe a) -> m () -> m ()
whenNothingM_ m (Maybe a)
mm m ()
action = m (Maybe a)
mm forall (m :: * -> *) a b. Monad m => m a -> (a -> m b) -> m b
>>= \Maybe a
m -> forall (f :: * -> *) a. Applicative f => Maybe a -> f () -> f ()
whenNothing_ Maybe a
m m ()
action
{-# INLINE whenNothingM_ #-}