deepseq-bounded-0.6.1.0: src/Control/DeepSeq/Bounded/NFDataP.hs
-------------------------------------------------------------------------------
{- 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 <rasfar@gmail.com>
-- 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 <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.
--
-- 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 <http://hackage.haskell.org/package/deepseq-bounded-0.6.0.0/docs/Control-DeepSeq-Bounded-NFDataPDyn.html NFDataPDyn> 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/
-- <http://hackage.haskell.org/package/deepseq-bounded-0.6.0.0/docs/Control-DeepSeq-Bounded-NFDataPDyn.html NFDataPDyn> /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 <rasfar@gmail.com>
-- 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 <deepseq-bounded>
-- 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 <deepseq-bounded>
-- 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
-------------------------------------------------------------------------------