{-# LANGUAGE Safe #-} {- | Copyright: (c) 2016 Stephen Diehl (c) 2016-2018 Serokell (c) 2018-2020 Kowainik SPDX-License-Identifier: MIT Maintainer: Kowainik <xrom.xkov@gmail.com> Stability: Stable Portability: Portable Utility functions to work with 'Relude.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.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 'whenNothingM'. >>> 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 'whenNothingM_'. >>> 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 #-}