------------------------------------------------------------------------------- {- 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 -- 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 , -- potentially infinite values of coinductive data types -- are supported by principled bounding of deep evaluation. -- -- Refer to comments in the 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 ). ------------------------------------------------------------------------------- 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 , module Control.DeepSeq.Bounded.Flags ) where ------------------------------------------------------------------------------- import Control.DeepSeq.Bounded.Flags #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 -------------------------------------------------------------------------------