{-# 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

This module contains useful functions to evaluate expressions to weak-head
normal form (WHNF) or just normal form (NF). Useful to force traces or @error@s
inside monadic computations or to remove space leaks.
-}

module Relude.DeepSeq
    ( -- * "Control.DeepSeq" reexports
      NFData (..)
    , deepseq
    , force
    , ($!!)

      -- * Evaluation
    , evaluateNF
    , evaluateNF_
    , evaluateWHNF
    , evaluateWHNF_
    ) where

import Control.DeepSeq (NFData (..), deepseq, force, ($!!))

import Relude.Base (IO, seq)
import Relude.Function ((.))
import Relude.Monad (MonadIO, liftIO, (<$!>))

import qualified Control.Exception.Base (evaluate)


-- $setup
-- >>> import Relude

{- | Lifted alias for 'Control.Exception.Base.evaluate' with clearer name.

>>> let list = [1..5] :: [Int]
>>> :sprint list
list = _
>>> () <$ evaluateWHNF list
>>> :sprint list
list = 1 : _
-}
evaluateWHNF :: MonadIO m => a -> m a
evaluateWHNF :: a -> m a
evaluateWHNF = IO a -> m a
forall (m :: * -> *) a. MonadIO m => IO a -> m a
liftIO (IO a -> m a) -> (a -> IO a) -> a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> IO a
forall a. a -> IO a
Control.Exception.Base.evaluate
{-# INLINE evaluateWHNF #-}
{-# SPECIALIZE evaluateWHNF :: a -> IO a #-}

{- | Like 'evaluateWHNF' but discards value.

>>> let list = [1..5] :: [Int]
>>> :sprint list
list = _
>>> evaluateWHNF_ list
>>> :sprint list
list = 1 : _
-}
evaluateWHNF_ :: MonadIO m => a -> m ()
evaluateWHNF_ :: a -> m ()
evaluateWHNF_ what :: a
what = (a -> () -> ()
forall a b. a -> b -> b
`seq` ()) (a -> ()) -> m a -> m ()
forall (m :: * -> *) a b. Monad m => (a -> b) -> m a -> m b
<$!> a -> m a
forall (m :: * -> *) a. MonadIO m => a -> m a
evaluateWHNF a
what
{-# INLINE evaluateWHNF_ #-}
{-# SPECIALIZE evaluateWHNF_ :: a -> IO () #-}

{- | Alias for @evaluateWHNF . force@ with clearer name.

>>> let list = [1..5] :: [Int]
>>> :sprint list
list = _
>>> () <$ evaluateNF list
>>> :sprint list
list = [1,2,3,4,5]
-}
evaluateNF :: (NFData a, MonadIO m) => a -> m a
evaluateNF :: a -> m a
evaluateNF = a -> m a
forall (m :: * -> *) a. MonadIO m => a -> m a
evaluateWHNF (a -> m a) -> (a -> a) -> a -> m a
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> a
forall a. NFData a => a -> a
force
{-# INLINE evaluateNF #-}
{-# SPECIALIZE evaluateNF :: NFData a => a -> IO a #-}

{- | Alias for @evaluateWHNF . rnf@. Similar to 'evaluateNF'
-- but discards resulting value.

>>> let list = [1..5] :: [Int]
>>> :sprint list
list = _
>>> evaluateNF_ list
>>> :sprint list
list = [1,2,3,4,5]
-}
evaluateNF_ :: (NFData a, MonadIO m) => a -> m ()
evaluateNF_ :: a -> m ()
evaluateNF_ = () -> m ()
forall (m :: * -> *) a. MonadIO m => a -> m a
evaluateWHNF (() -> m ()) -> (a -> ()) -> a -> m ()
forall b c a. (b -> c) -> (a -> b) -> a -> c
. a -> ()
forall a. NFData a => a -> ()
rnf
{-# INLINE evaluateNF_ #-}
{-# SPECIALIZE evaluateNF_ :: NFData a => a -> IO () #-}