{-# LANGUAGE CPP #-} {-# LANGUAGE Trustworthy #-} {-# LANGUAGE TypeFamilies #-} -- | Reexporting useful monadic stuff. module Monad ( module Monad.Maybe , module Monad.Either , module Monad.Trans , Monad ((>>=), (>>), return) , MonadFail (fail) , MonadPlus (..) , (=<<) , (>=>) , (<=<) , forever , join , mfilter , filterM , mapAndUnzipM , zipWithM , zipWithM_ , foldM , foldM_ , replicateM , replicateM_ , concatMapM , concatForM , guard , when , unless , allM , anyM , andM , orM , liftM , liftM2 , liftM3 , liftM4 , liftM5 , ap , (<$!>) ) where import Monad.Either import Monad.Maybe import Monad.Trans import Base (IO, seq) import Control.Applicative (Applicative (pure)) import Data.Function ((.)) import Data.Functor (fmap) import Data.Traversable (Traversable (traverse)) import Prelude (Bool (..), flip) #if __GLASGOW_HASKELL__ >= 710 import Control.Monad hiding (fail, (<$!>)) #else import Control.Monad hiding (fail) #endif #if __GLASGOW_HASKELL__ >= 800 import Control.Monad.Fail (MonadFail (..)) #else import Prelude (Maybe (Nothing), String) import qualified Prelude as P (fail) import Text.ParserCombinators.ReadP (ReadP) import Text.ParserCombinators.ReadPrec (ReadPrec) #endif import Containers (Element, NontrivialContainer, toList) -- | Lifting bind into a monad. Generalized version of @concatMap@ -- that works with a monadic predicate. Old and simpler specialized to list -- version had next type: -- -- @ -- concatMapM :: Monad m => (a -> m [b]) -> [a] -> m [b] -- @ concatMapM :: (Applicative q, Monad m, Traversable m) => (a -> q (m b)) -> m a -> q (m b) concatMapM f = fmap join . traverse f {-# INLINE concatMapM #-} -- | Like 'concatMapM', but has its arguments flipped, so can be used -- instead of the common @fmap concat $ forM@ pattern. concatForM :: (Applicative q, Monad m, Traversable m) => m a -> (a -> q (m b)) -> q (m b) concatForM = flip concatMapM {-# INLINE concatForM #-} -- | Stricter version of 'Data.Functor.<$>'. (<$!>) :: Monad m => (a -> b) -> m a -> m b f <$!> m = do x <- m let z = f x z `seq` return z {-# INLINE (<$!>) #-} -- | Monadic and constrained to 'NonTrivialContainer' version of 'Prelude.and'. -- -- >>> andM [Just True, Just False] -- Just False -- >>> andM [Just True] -- Just True -- >>> andM [Just True, Just False, Nothing] -- Just False -- >>> andM [Just True, Nothing] -- Nothing -- >>> andM [putStrLn "1" >> pure True, putStrLn "2" >> pure False, putStrLn "3" >> undefined] -- 1 -- 2 -- False andM :: (NontrivialContainer f, Element f ~ m Bool, Monad m) => f -> m Bool andM = go . toList where go [] = pure True go (p:ps) = do q <- p if q then go ps else pure False -- | Monadic and constrained to 'NonTrivialContainer' version of 'Prelude.or'. -- -- >>> orM [Just True, Just False] -- Just True -- >>> orM [Just True, Nothing] -- Just True -- >>> orM [Nothing, Just True] -- Nothing orM :: (NontrivialContainer f, Element f ~ m Bool, Monad m) => f -> m Bool orM = go . toList where go [] = pure False go (p:ps) = do q <- p if q then pure True else go ps -- | Monadic and constrained to 'NonTrivialContainer' version of 'Prelude.all'. -- -- >>> allM (readMaybe >=> pure . even) ["6", "10"] -- Just True -- >>> allM (readMaybe >=> pure . even) ["5", "aba"] -- Just False -- >>> allM (readMaybe >=> pure . even) ["aba", "10"] -- Nothing allM :: (NontrivialContainer f, Monad m) => (Element f -> m Bool) -> f -> m Bool allM p = go . toList where go [] = pure True go (x:xs) = do q <- p x if q then go xs else pure False -- | Monadic and constrained to 'NonTrivialContainer' version of 'Prelude.any'. -- -- >>> anyM (readMaybe >=> pure . even) ["5", "10"] -- Just True -- >>> anyM (readMaybe >=> pure . even) ["10", "aba"] -- Just True -- >>> anyM (readMaybe >=> pure . even) ["aba", "10"] -- Nothing anyM :: (NontrivialContainer f, Monad m) => (Element f -> m Bool) -> f -> m Bool anyM p = go . toList where go [] = pure False go (x:xs) = do q <- p x if q then pure True else go xs {-# SPECIALIZE andM :: [IO Bool] -> IO Bool #-} {-# SPECIALIZE orM :: [IO Bool] -> IO Bool #-} {-# SPECIALIZE anyM :: (a -> IO Bool) -> [a] -> IO Bool #-} {-# SPECIALIZE allM :: (a -> IO Bool) -> [a] -> IO Bool #-} #if __GLASGOW_HASKELL__ < 800 -- | Class for 'Monad's that can 'fail'. -- Copied from 'fail' by Herbert Valerio Riedel (the library is under BSD3). class Monad m => MonadFail m where fail :: String -> m a instance MonadFail Maybe where fail _ = Nothing instance MonadFail [] where fail _ = [] instance MonadFail IO where fail = P.fail instance MonadFail ReadPrec where fail = P.fail -- = P (\_ -> fail s) instance MonadFail ReadP where fail = P.fail #endif