-- ------------------------------------------------------------

{- |
   Module     : Control.FlatSeq
   Copyright  : Copyright (C) 2011 Uwe Schmidt
   License    : MIT

   Maintainer : Uwe Schmidt (uwe\@fh-wedel.de)
   Stability  : experimental
   Portability: portable

   Force evaluation like deepseq in Control.DeepSeq,
   but control the depth of evaluation.
   flatseq may evaluate more than seq but less than deepseq

-}

-- ------------------------------------------------------------

module Control.FlatSeq
where

import Data.Word

-- ------------------------------------------------------------

infixr 0 $!!

($!!)                           :: WNFData a => (a -> b) -> a -> b
f $!! x                         = rwnf x `seq` f x
{-# INLINE ($!!) #-}

flatseq                         :: WNFData a => a -> b -> b
flatseq a b                     = rwnf a `seq` b
{-# INLINE flatseq #-}

rlnf                            :: (a -> ()) -> [a] -> ()
rlnf _ []                       = ()
rlnf r (x:xs)                   = r x `seq` rlnf r xs
{-# INLINE rlnf #-}

-- | A class of types that can be partially evaluated, but evaluation can be propagated deeper than WHNF

class WNFData a where
    -- | Default for rwnf is reduction to WHNF
    rwnf                        :: a -> ()
    rwnf a                      = a `seq` ()
    {-# INLINE rwnf #-}

    -- | Default for rwnf2 is rwnf
    rwnf2                       :: a -> ()
    rwnf2                       = rwnf
    {-# INLINE rwnf2 #-}

instance WNFData Int
instance WNFData Integer
instance WNFData Float
instance WNFData Double

instance WNFData Char
instance WNFData Bool
instance WNFData ()

instance WNFData Word
instance WNFData Word8
instance WNFData Word16
instance WNFData Word32
instance WNFData Word64

instance WNFData a => WNFData [a] where
    rwnf []                     = ()
    rwnf (x:xs)                 = x `seq` rwnf xs
    {-# INLINE rwnf #-}

instance (WNFData a, WNFData b) => WNFData (a,b) where
    rwnf (x,y)                  = rwnf x `seq` rwnf y
    {-# INLINE rwnf #-}

instance (WNFData a, WNFData b, WNFData c) => WNFData (a,b,c) where
    rwnf (x,y,z)                = rwnf x `seq` rwnf y `seq` rwnf z
    {-# INLINE rwnf #-}

instance (WNFData a, WNFData b, WNFData c, WNFData d) => WNFData (a,b,c,d) where
    rwnf (x1,x2,x3,x4)          = rwnf x1 `seq`
                                  rwnf x2 `seq`
                                  rwnf x3 `seq`
                                  rwnf x4
    {-# INLINE rwnf #-}

-- ------------------------------------------------------------