deepseq-bounded-0.7.0.0: src/Control/DeepSeq/Bounded.hs
-------------------------------------------------------------------------------
{- LANGUAGE CPP #-}
#if PROVIDE_DATA_FAMILY
{-# LANGUAGE CPP #-}
{-# LANGUAGE TypeFamilies #-}
{- LANGUAGE TypeSynonymInstances #-}
{-# LANGUAGE FlexibleInstances #-}
{- LANGUAGE DatatypeContexts #-}
#endif
-------------------------------------------------------------------------------
-- |
-- Module : Control.DeepSeq.Bounded
-- Copyright : Andrew G. Seniuk 2014-2015
-- License : BSD-style (see the file LICENSE)
--
-- Maintainer : Andrew Seniuk <rasfar@gmail.com>
-- Stability : provisional
-- Portability : portable (but GHC for a few modules using generics)
--
-- We provide forcing functions which take a non-strict value
-- of a datatype, and force its evaluation in a pricipled way.
-- As with 'NFData', one should bear in mind the difference
-- between forcing and demand: in order for your forcing to
-- take effect, demand must be placed on the forcing function
-- itself by the course of execution.
--
-- Artificial forcing is most commonly used to suppress space
-- leak, but it has many uses besides.
-- Another is to ensure that exceptions hidden within lazy
-- fields of a data structure don't leak outside the scope of the
-- exception handler; another is to force evaluation of a data structure in
-- one thread, before passing it to another thread (preventing work moving
-- to the wrong threads, a form of /time leak/).
--
-- Unlike <http://hackage.haskell.org/package/deepseq/docs/Control-DeepSeq.html DeepSeq>,
-- potentially infinite values of coinductive data types
-- are supported by principled bounding of deep evaluation.
--
-- Refer to comments in the <http://hackage.haskell.org/package/deepseq deepseq> package for more information on how
-- artificial forcing can be useful.
--
-- Recently, control (static or dynamic) of parallelisation has been added.
-- Control of evaluation order is also supported (via <http://hackage.haskell.org/package/parallel/docs/Control-Parallel.html#v:pseq pseq>).
-------------------------------------------------------------------------------
module Control.DeepSeq.Bounded
(
-- * Forced evaluation to an arbitrary finite depth
module Control.DeepSeq.Bounded.NFDataN
-- * Forced evaluation over a pattern (arbitrary finite, or dynamic)
, module Control.DeepSeq.Bounded.Pattern
, module Control.DeepSeq.Bounded.Compile
, module Control.DeepSeq.Bounded.PatUtil -- re-exports the former
, module Control.DeepSeq.Bounded.NFDataP -- re-exports both
#if USE_SOP
, module Control.DeepSeq.Bounded.NFDataPDyn -- re-exps. all 3 above
#endif
-- XXX On second thoughts, I don't want to depend on containers
-- package just to provide a rose tree data type!...
-- I don't export Data.Tree; ideally the API would never
-- require the user to work at that low level, but if
-- necessary they can import Data.Tree themselves.
, Rose(..)
-- * Forced evaluation "molecular style"
, module Control.DeepSeq.Bounded.Seqable
#if ! HASKELL98_FRAGMENT
-- * Generic deriving support via "Generics.SOP"
#if USE_SOP
, module Control.DeepSeq.Bounded.Generic.GSeqable
#endif
, module Control.DeepSeq.Bounded.Generic.GNFDataN
#if USE_SOP
, module Control.DeepSeq.Bounded.Generic.GNFDataP
#endif
#endif
#if USE_WW_DEEPSEQ
-- * Re-exported
, module Control.DeepSeq
#endif
-- (I'm not sure what the exact bound is, but 7.6.3 is too low.)
#if __GLASGOW_HASKELL__ >= 708
#if PROVIDE_DATA_FAMILY
-- * \"I can has data family?...\"
, FF(..)
#endif
#endif
)
where
-------------------------------------------------------------------------------
#if PROVIDE_DATA_FAMILY
-- Remarkable, this is not already in scope by re-export!
import Generics.SOP ( Generic )
#endif
import Control.DeepSeq.Bounded.Seqable
import Control.DeepSeq.Bounded.NFDataN
import Control.DeepSeq.Bounded.Pattern
import Control.DeepSeq.Bounded.Compile
import Control.DeepSeq.Bounded.PatUtil
import Control.DeepSeq.Bounded.NFDataP
#if USE_SOP
import Control.DeepSeq.Bounded.NFDataPDyn
#endif
#if ! HASKELL98_FRAGMENT
-- In its own category, relative to GNFDataN and GNFDataP.
#if USE_SOP
import Control.DeepSeq.Bounded.Generic.GSeqable
#endif
import Control.DeepSeq.Bounded.Generic.GNFDataN
#if USE_SOP
import Control.DeepSeq.Bounded.Generic.GNFDataP
#endif
#endif
#if USE_WW_DEEPSEQ
import Control.DeepSeq
#endif
-------------------------------------------------------------------------------
-- Lest I forget WHY -- now, you can express
--
-- "composition of partially-applied forcing functions commutes"
--
-- directly in Haskell (and compute with it, etc)!...
-- (I'm not sure what the exact bound is, but 7.6.3 is too low.)
#if __GLASGOW_HASKELL__ >= 708
#if PROVIDE_DATA_FAMILY
-- I do believe this came out as a nice first attempt
-- at using any type extensions! After 25 years of
-- functional programming, and 15 in Haskell, I've
-- never used anything non-H98 in my own code, unless
-- a library I used forced me to. Never in my own code!
-- Until today... / I can see why people get excited
-- about this stuff, it's definitely "elegant"!
class FF k where
data F k :: * -> *
-- | The constraints could probably shrink to just 'Generic' with
-- a bit of work... In fact, trying it now -- to do away with NFDataN
-- and NFDataP classes, and just "alias the SOP generic functions",
-- as did in Seqable... [Fail. for now]
phi :: (
#if JUST_ALIAS_GSEQABLE
Generic v
#else
Seqable v
#endif
, NFDataN v
, NFDataP v
) => k -> F k v -> v
instance FF SeqNode where -- Seqable[/Generic]
data F SeqNode v = FSeqNode v
phi k (FSeqNode m) = force_ k m
instance FF Int where -- NFDataN
data F Int v = FInt v
phi k (FInt m) = forcen k m
instance FF Pattern where -- NFDataP
data F Pattern v = FPattern v
phi k (FPattern m) = forcep_ k m
#if 0
instance (FF Pattern, FF a) => FF (Pattern,a) where
data F (Pattern, a) = FPattern v
phi (pat,a) (FPattern m) = forcep k m
#endif
#endif
#endif
-------------------------------------------------------------------------------