packages feed

data-forced-0.1.0.0: src/Data/Forced.hs

{-# Language ExplicitForAll, UnliftedDatatypes, PatternSynonyms, GADTSyntax #-}

module Data.Forced
  ( Strict(..)
  , ForcedWHNF
  , pattern ForcedWHNF
  , ForcedNF
  , pattern ForcedNF
  , strictlyWHNF
  , strictlyNF
  ) where

import Data.Elevator ( UnliftedType, LiftedType )
import Control.DeepSeq

type Strict :: LiftedType -> UnliftedType
data Strict a where
  Strict :: !a -> Strict a

{- The invariants of @ForcedWHNF@ and @ForcedNF@ depends on the constructors
not being exported. The only way to construct these value is through the CBV
functions. Pattern matching is done via a unidirectional pattern.
-}
newtype ForcedWHNF a = ForcedOuter a

pattern ForcedWHNF :: forall a. a -> ForcedWHNF a
pattern ForcedWHNF a <- ForcedOuter a

newtype ForcedNF a = ForcedFull a

pattern ForcedNF :: forall a. a -> ForcedNF a
pattern ForcedNF a <- ForcedFull a

{- | This is a CBV function. Evaluates the argument to WHNF before
returning.
-}
strictlyWHNF :: forall a. a -> Strict (ForcedWHNF a)
strictlyWHNF a = Strict (ForcedOuter a)

{- | This is a CBV function. Evaluates the argument to NF before returning.
-}
strictlyNF :: forall a. NFData a => a -> Strict (ForcedNF a)
strictlyNF a = Strict (ForcedFull (rnf a `seq` a))