relude-1.2.0.0: src/Relude/Monad/Trans.hs
{-# LANGUAGE Trustworthy #-}
{- |
Module : Relude.Monad.Trans
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
Monad transformers utilities.
-}
module Relude.Monad.Trans
( -- * Convenient functions to work with 'Reader' monad
usingReader
, usingReaderT
, etaReaderT
-- * Convenient functions to work with 'State' monad
, evaluatingState
, evaluatingStateT
, executingState
, executingStateT
, usingState
, usingStateT
-- * Lifted to Transformers
, hoistMaybe
, hoistEither
) where
import GHC.Exts (oneShot)
import Relude.Applicative (Applicative (pure))
import Relude.Container.Reexport (fst, snd)
import Relude.Function (flip, (.))
import Relude.Functor (Functor, (<$>))
import Relude.Monad.Reexport (Either, ExceptT (..), Maybe, MaybeT (..), Reader, ReaderT (..), State,
StateT, runReader, runReaderT, runState, runStateT)
-- $setup
-- >>> import Relude
{- | Shorter and more readable alias for @flip runReaderT@.
>>> usingReaderT 42 $ asks (+5)
47
-}
usingReaderT :: r -> ReaderT r m a -> m a
usingReaderT = flip runReaderT
{-# INLINE usingReaderT #-}
{- | Shorter and more readable alias for @flip runReader@.
>>> usingReader 42 $ asks (+5)
47
-}
usingReader :: r -> Reader r a -> a
usingReader = flip runReader
{-# INLINE usingReader #-}
{- | This function helps with optimizing performance when working with
the 'ReaderT' transformer. If you have code like below, that is
called in a loop
@
step :: Instruction -> 'ReaderT' Config IO Result
step instruction = __case__ instruction __of__
Add -> __do__ stuff ...
Del -> __do__ stuff ...
@
you can improve performance of your Haskell applications by using
'etaReaderT' in the following way:
@
step :: Instruction -> 'ReaderT' Config IO Result
step instruction = 'etaReaderT' $ __case__ instruction __of__
Add -> __do__ stuff ...
Del -> __do__ stuff ...
@
For a detailed explanation, refer to the following blog post:
* <https://www.joachim-breitner.de/blog/763-Faster_Winter_5__Eta-Expanding_ReaderT Faster Winter 5: Eta-Expanding ReaderT (by Joachim Breitner)>
@since 0.7.0.0
-}
etaReaderT :: ReaderT r m a -> ReaderT r m a
etaReaderT = ReaderT . oneShot . runReaderT
{-# INLINE etaReaderT #-}
{- | Shorter and more readable alias for @flip runStateT@.
>>> usingStateT 0 $ put 42 >> pure False
(False,42)
-}
usingStateT :: s -> StateT s m a -> m (a, s)
usingStateT = flip runStateT
{-# INLINE usingStateT #-}
-- | Shorter and more readable alias for @flip runState@.
usingState :: s -> State s a -> (a, s)
usingState = flip runState
{-# INLINE usingState #-}
{- | Alias for @flip evalStateT@. It's not shorter but sometimes
more readable. Done by analogy with @using*@ functions family.
-}
evaluatingStateT :: Functor f => s -> StateT s f a -> f a
evaluatingStateT s st = fst <$> usingStateT s st
{-# INLINE evaluatingStateT #-}
{- | Alias for @flip evalState@. It's not shorter but sometimes
more readable. Done by analogy with @using*@ functions family.
-}
evaluatingState :: s -> State s a -> a
evaluatingState s st = fst (usingState s st)
{-# INLINE evaluatingState #-}
{- | Alias for @flip execStateT@. It's not shorter but sometimes
more readable. Done by analogy with @using*@ functions family.
-}
executingStateT :: Functor f => s -> StateT s f a -> f s
executingStateT s st = snd <$> usingStateT s st
{-# INLINE executingStateT #-}
{- | Alias for @flip execState@. It's not shorter but sometimes
more readable. Done by analogy with @using*@ functions family.
-}
executingState :: s -> State s a -> s
executingState s st = snd (usingState s st)
{-# INLINE executingState #-}
{- | Lift a 'Maybe' to the 'MaybeT' monad
@since 0.3.0
-}
hoistMaybe :: Applicative m => Maybe a -> MaybeT m a
hoistMaybe m = MaybeT (pure m)
{-# INLINE hoistMaybe #-}
{- | Lift a 'Either' to the 'ExceptT' monad
@since 0.3.0
-}
hoistEither :: Applicative m => Either e a -> ExceptT e m a
hoistEither e = ExceptT (pure e)
{-# INLINE hoistEither #-}