------------------------------------------------------------------------------- {- LANGUAGE CPP #-} ------------------------------------------------------------------------------- #if NEW_IMPROVED_PATTERN_GRAMMAR -- | -- Module : Control.DeepSeq.Bounded.NFDataP -- Copyright : Andrew G. Seniuk 2014-2015 -- License : BSD-style (see the file LICENSE) -- -- Maintainer : Andrew Seniuk -- Stability : provisional -- Portability : portable -- -- This module provides an overloaded function, 'deepseqp', for partially -- (or fully) evaluating data structures to bounded depth via pattern -- matching on term shape, and on class, type, and constructor names. -- -- There are two ways to use this API. -- -- (1) You can use the 'PatNode' constructors directly. -- -- (2) You can compile your patterns from strings in a concise -- embedded language. -- -- There's no difference in expressive power, but use of the DSL -- is recommended, because the embedded 'Pattern' compiler can catch -- some errors that GHC cannot (using 'PatNode' constructors explicitly). -- Also, the pattern strings are easier to read and write. -- -- With some qualifications (concerning 'WI' nodes, and 'PatNodeAttrs' -- configuration), composition fuses, and what's more, it's commutative... -- -- __Motivation__ -- -- A typical use is to ensure any exceptions hidden within lazy -- fields of a data structure do not 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). Unlike , potentially infinite values of coinductive -- data types are supported by principled bounding of deep evaluation. -- -- It is also useful for diagnostic purposes when trying to understand -- and manipulate space\/time trade-offs in lazy code, -- and as an optimal substitute for 'deepseq' -- (where \"optimal\" doesn't include changing the code to remove -- the need for artificial forcing!). -- -- 'deepseqp' with optimal patterns is usually a better solution -- even than stict fields in your data structures, because the -- latter will behave strictly everywhere the constructors -- are used, instead of just where its laziness is problematic. -- -- There may be possible applications to the prevention of resource leaks -- in lazy streaming, but I'm not certain. -- -- __Semantics__ -- -- (For additional details, see "Control.DeepSeq.Bounded.Pattern".) -- -- 'deepseqp' and friends artifically force evaluation of a term -- so long as the pattern matches. -- -- A mismatch occurs at a pattern node when the corresponding constructor node either: -- -- * has arity different than the number of subpatterns (only when subpatterns given) -- -- * has class\/type\/name not named in the constraint (only when constraint given) -- -- A mismatch will cause evaluation down that branch to stop, but any -- upstream matching/forcing will continue uninterrupted. -- / (This behaviour can now be changed with 'PatNodeAttrs', available since 0.6.) / -- -- Note that patterns may extend beyond the values they match against, -- without incurring any mismatch. This semantics is not the only -- possible, but bear in mind that order of evaluation is nondeterministic, -- barring further measures. -- / (This behaviour can also now be changed with 'PatNodeAttrs'.) / -- -- See also for another approach, which dynamically -- generates forcing patterns, and can depend on value info -- (in addition to type info). -- / (These dynamic aspects never received the attention I intended to give them, I got so caught up in seqaid, which offers similar features. Hopefully actual use of these tools in the near future will give me some perspective on whether/ -- /should get attention.) / -- #else -- | -- Module : Control.DeepSeq.Bounded.NFDataP -- Copyright : Andrew G. Seniuk 2014-2015 -- License : BSD-style (see the file LICENSE) -- -- Maintainer : Andrew Seniuk -- Stability : provisional -- Portability : portable -- -- This module provides an overloaded function, 'deepseqp', for partially -- (or fully) evaluating data structures to bounded depth via pattern -- matching on term shape, and on class, type, and constructor names. -- -- There are two ways to use this API. -- -- (1) You can use the 'PatNode' constructors directly. -- -- (2) You can compile your patterns from strings in a concise -- embedded language. -- -- There's no difference in expressive power, but use of the DSL -- is recommended, because the embedded 'Pattern' compiler can catch -- some errors that GHC cannot (using 'PatNode' constructors explicitly). -- Also, the pattern strings are easier to read and write. -- -- __Motivation__ -- -- A typical use is to ensure any exceptions hidden within lazy -- fields of a data structure do not 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). Unlike "DeepSeq", potentially infinite values of coinductive -- data types are supported by principled bounding of deep evaluation. -- -- It is also useful for diagnostic purposes when trying to understand -- and manipulate space\/time trade-offs in lazy code, -- and as an optimal substitute for 'deepseq' -- (where \"optimal\" doesn't include changing the code to remove -- the need for artificial forcing!). -- -- 'deepseqp' with optimal patterns is usually a better solution -- even than stict fields in your data structures, because the -- latter will behave strictly everywhere the constructors -- are used, instead of just where its laziness is problematic. -- -- There may be possible applications to the prevention of resource leaks -- in lazy streaming, but I'm not certain. -- -- __Semantics__ -- -- (For additional details, see "Control.DeepSeq.Bounded.Pattern".) -- -- 'deepseqp' and friends artifically force evaluation of a term -- so long as the pattern matches. -- -- A mismatch occurs at a pattern node when the corresponding constructor node either: -- -- * has arity different than the number of subpatterns (only when subpatterns given) -- -- * has class\/type\/name not named in the constraint (only when constraint given) -- -- A mismatch will cause evaluation down that branch to stop, but any -- upstream matching/forcing will continue uninterrupted. -- Note that patterns may extend beyond the values they match against, -- without incurring any mismatch. This semantics is not the only -- possible, but bear in mind that order of evaluation is nondeterministic, -- barring further measures. -- -- See also "NFDataPDyn" for another approach, which dynamically -- generates forcing patterns, and can depend on value info -- (in addition to type info). -- #endif ------------------------------------------------------------------------------- module Control.DeepSeq.Bounded.NFDataP ( #if NEW_IMPROVED_PATTERN_GRAMMAR -- * Pattern-bounded analogues of 'deepseq' and 'force' deepseqp, forcep -- take String arg (pattern DSL) -- * Avoid DSL compilation overhead -- -- However, we don't anticipate that this overhead would be -- significant in most applications, because using -- in a tight loop would only be done for diagnostic purposes. , deepseqp_, forcep_ -- take Pattern structure arg -- * A custom exception, raised by choice 'PatNode's, that can be caught in the caller #if USE_PING_PATNODE , DeepSeqBounded_PingException(..) #endif -- * Related modules re-exported , module Control.DeepSeq.Bounded.Pattern , module Control.DeepSeq.Bounded.PatUtil -- actually exports former -- * Class of things that can be evaluated over an arbitrary finite pattern , NFDataP(..) -- * Shared with GNFDataP (internal use) , handleAttrs -- used by GNFDataP at least #else -- * Pattern-bounded analogues of 'deepseq' and 'force' deepseqp, forcep -- take String arg (pattern DSL) -- * Avoid DSL compilation overhead -- -- However, we don't anticipate that this overhead would be -- significant in most applications, because using -- in a tight loop would only be done for diagnostic purposes. , deepseqp_, forcep_ -- take Pattern structure arg #if 0 -- Don't bother, really. , deepseqpM, forcepM -- return lifted argument so can cope with bottom , deepseqpM_, forcepM_ #endif -- * Related modules re-exported , module Control.DeepSeq.Bounded.Pattern , module Control.DeepSeq.Bounded.PatUtil -- actually exports former -- * Class of things that can be evaluated over an arbitrary finite pattern , NFDataP(..) #endif --- #if NEW_IMPROVED_PATTERN_GRAMMAR --- module Control.DeepSeq.Bounded.NFDataP_new_grammar , --- #else --- module Control.DeepSeq.Bounded.NFDataP_old_grammar , --- #endif ) where ------------------------------------------------------------------------------- #if NEW_IMPROVED_PATTERN_GRAMMAR import Control.DeepSeq.Bounded.NFDataP_new_grammar #else import Control.DeepSeq.Bounded.NFDataP_old_grammar #endif -- Necessity seems like a Haddock bug, as it is both imported -- and exported by PatUtil_{old,new}_*.hs. import Control.DeepSeq.Bounded.Pattern import Control.DeepSeq.Bounded.PatUtil -------------------------------------------------------------------------------