{-# LANGUAGE Safe #-}

{- |
Module                  : Relude.Monad
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

Reexporting useful monadic stuff.
-}

module Relude.Monad
    ( module Relude.Monad.Reexport
      -- $reexport
    , module Relude.Monad.Maybe
      -- $maybe
    , module Relude.Monad.Either
      -- $either
    , module Relude.Monad.Trans
      -- $trans
    , chainedTo
    , infinitely
    ) where

import Relude.Monad.Either
import Relude.Monad.Maybe
import Relude.Monad.Reexport
import Relude.Monad.Trans
import Control.Applicative (Applicative)
import Relude.Base (Void)


-- $setup
-- >>> import Relude

{- | For chaining monadic operations in forward applications using '(&)'
Named version of '=<<'.

>>> Just [ 1 :: Int ] & chainedTo (viaNonEmpty head)
Just 1
>>> Nothing & chainedTo (viaNonEmpty head)
Nothing

@since 0.5.0
-}
chainedTo :: Monad m => (a -> m b) -> m a -> m b
chainedTo = (=<<)
{-# INLINE chainedTo #-}

{- | Repeat a monadic action indefinitely.

This is a more type safe version of 'forever', which has a convenient
but unsafe type.

Consider the following two examples. In the @getIntForever@ functions, it
falsely expects 'Int' as the result of the 'forever' function. But it would need
to wait *forever* to get that, and this mistake won't be caught by the type
system and compiler:

@
getIntForever :: IO Int
getIntForever = do
    i <- forever $ do ...
    pure i
@

In contrast, using 'infinitely' instead of 'forever' in 'foo' is a type error.

@since 1.0.0.0
-}
infinitely :: Applicative f => f a -> f Void
infinitely = forever
{-# INLINE infinitely #-}

{- $reexport
Reexports functions to work with different monads.
-}
{- $maybe
Provided new combinators to work with 'Relude.Monad.Reexport.Maybe' data type.
-}
{- $either
Provided new combinators to work with 'Relude.Monad.Reexport.Either' data type.
-}
{- $trans
Monad transformers functions and combinators.
-}
