Safe Haskell | None |
---|---|
Language | Haskell2010 |
Synopsis
- seq :: a -> b -> b
- lazy :: a -> a
- ($!) :: (a -> b) -> a -> b
- evaluate :: a -> IO a
- data NF a
- makeNF :: NFData a => a -> NF a
- getNF :: NF a -> a
- class NFData a where
- deepseq :: NFData a => a -> b -> b
- force :: NFData a => a -> a
- ($!!) :: NFData a => (a -> b) -> a -> b
- (<$!!>) :: (Monad m, NFData b) => (a -> b) -> m a -> m b
- rwhnf :: a -> ()
- class NFData1 (f :: * -> *) where
- rnf1 :: (NFData1 f, NFData a) => f a -> ()
- class NFData2 (p :: * -> * -> *) where
- rnf2 :: (NFData2 p, NFData a, NFData b) => p a b -> ()
- data Eval a
- runEval :: Eval a -> a
- type Strategy a = a -> Eval a
- using :: a -> Strategy a -> a
- withStrategy :: Strategy a -> a -> a
- dot :: Strategy a -> Strategy a -> Strategy a
- rseq :: Strategy a
- rdeepseq :: NFData a => Strategy a
- evalTraversable :: Traversable t => Strategy a -> Strategy (t a)
- evalList :: Strategy a -> Strategy [a]
- evalTuple2 :: Strategy a -> Strategy b -> Strategy (a, b)
- evalTuple3 :: Strategy a -> Strategy b -> Strategy c -> Strategy (a, b, c)
- evalTuple4 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy (a, b, c, d)
- evalTuple5 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy (a, b, c, d, e)
- evalTuple6 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy (a, b, c, d, e, f)
- evalTuple7 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy (a, b, c, d, e, f, g)
- evalTuple8 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy (a, b, c, d, e, f, g, h)
- evalTuple9 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy h -> Strategy i -> Strategy (a, b, c, d, e, f, g, h, i)
Weak head normal form
The value of seq a b
is bottom if a
is bottom, and
otherwise equal to b
. In other words, it evaluates the first
argument a
to weak head normal form (WHNF). seq
is usually
introduced to improve performance by avoiding unneeded laziness.
A note on evaluation order: the expression seq a b
does
not guarantee that a
will be evaluated before b
.
The only guarantee given by seq
is that the both a
and b
will be evaluated before seq
returns a value.
In particular, this means that b
may be evaluated before
a
. If you need to guarantee a specific order of evaluation,
you must use the function pseq
from the "parallel" package.
The lazy
function restrains strictness analysis a little. The
call lazy e
means the same as e
, but lazy
has a magical
property so far as strictness analysis is concerned: it is lazy in
its first argument, even though its semantics is strict. After
strictness analysis has run, calls to lazy
are inlined to be the
identity function.
This behaviour is occasionally useful when controlling evaluation
order. Notably, lazy
is used in the library definition of
par
:
par :: a -> b -> b par x y = case (par# x) of _ -> lazy y
If lazy
were not lazy, par
would look strict in y
which
would defeat the whole purpose of par
.
($!) :: (a -> b) -> a -> b infixr 0 #
Strict (call-by-value) application operator. It takes a function and an argument, evaluates the argument to weak head normal form (WHNF), then calls the function with that value.
Evaluate the argument to weak head normal form.
evaluate
is typically used to uncover any exceptions that a lazy value
may contain, and possibly handle them.
evaluate
only evaluates to weak head normal form. If deeper
evaluation is needed, the force
function from Control.DeepSeq
may be handy:
evaluate $ force x
There is a subtle difference between
and evaluate
x
,
analogous to the difference between return
$!
xthrowIO
and throw
. If the lazy
value x
throws an exception,
will fail to return an
return
$!
xIO
action and will throw an exception instead.
, on the
other hand, always produces an evaluate
xIO
action; that action will throw an
exception upon execution iff x
throws an exception upon evaluation.
The practical implication of this difference is that due to the imprecise exceptions semantics,
(return $! error "foo") >> error "bar"
may throw either "foo"
or "bar"
, depending on the optimizations
performed by the compiler. On the other hand,
evaluate (error "foo") >> error "bar"
is guaranteed to throw "foo"
.
The rule of thumb is to use evaluate
to force or handle exceptions in
lazy values. If, on the other hand, you are forcing a lazy value for
efficiency reasons only and do not care about exceptions, you may
use
.return
$!
x
Normal form
NF
is an abstract data type representing data which has been
evaluated to normal form. Specifically, if a value of type
is in weak head normal form, then it is in reduced normal form;
alternatively, it is only necessary to NF
aseq
an
to assure that
it is fully evaluated.NF
a
Retrieves a
from a value of type
; this value
is guaranteed to be in normal form.NF
a
A class of types that can be fully evaluated.
Since: deepseq-1.1.0.0
rnf
should reduce its argument to normal form (that is, fully
evaluate all sub-components), and then return '()'.
Generic
NFData
deriving
Starting with GHC 7.2, you can automatically derive instances
for types possessing a Generic
instance.
Note: Generic1
can be auto-derived starting with GHC 7.4
{-# LANGUAGE DeriveGeneric #-} import GHC.Generics (Generic, Generic1) import Control.DeepSeq data Foo a = Foo a String deriving (Eq, Generic, Generic1) instance NFData a => NFData (Foo a) instance NFData1 Foo data Colour = Red | Green | Blue deriving Generic instance NFData Colour
Starting with GHC 7.10, the example above can be written more
concisely by enabling the new DeriveAnyClass
extension:
{-# LANGUAGE DeriveGeneric, DeriveAnyClass #-} import GHC.Generics (Generic) import Control.DeepSeq data Foo a = Foo a String deriving (Eq, Generic, Generic1, NFData, NFData1) data Colour = Red | Green | Blue deriving (Generic, NFData)
Compatibility with previous deepseq
versions
Prior to version 1.4.0.0, the default implementation of the rnf
method was defined as
rnf
a =seq
a ()
However, starting with deepseq-1.4.0.0
, the default
implementation is based on DefaultSignatures
allowing for
more accurate auto-derived NFData
instances. If you need the
previously used exact default rnf
method implementation
semantics, use
instance NFData Colour where rnf x = seq x ()
or alternatively
instance NFData Colour where rnf = rwhnf
or
{-# LANGUAGE BangPatterns #-} instance NFData Colour where rnf !_ = ()
Instances
deepseq :: NFData a => a -> b -> b #
deepseq
: fully evaluates the first argument, before returning the
second.
The name deepseq
is used to illustrate the relationship to seq
:
where seq
is shallow in the sense that it only evaluates the top
level of its argument, deepseq
traverses the entire data structure
evaluating it completely.
deepseq
can be useful for forcing pending exceptions,
eradicating space leaks, or forcing lazy I/O to happen. It is
also useful in conjunction with parallel Strategies (see the
parallel
package).
There is no guarantee about the ordering of evaluation. The
implementation may evaluate the components of the structure in
any order or in parallel. To impose an actual order on
evaluation, use pseq
from Control.Parallel in the
parallel
package.
Since: deepseq-1.1.0.0
a variant of deepseq
that is useful in some circumstances:
force x = x `deepseq` x
force x
fully evaluates x
, and then returns it. Note that
force x
only performs evaluation when the value of force x
itself is demanded, so essentially it turns shallow evaluation into
deep evaluation.
force
can be conveniently used in combination with ViewPatterns
:
{-# LANGUAGE BangPatterns, ViewPatterns #-} import Control.DeepSeq someFun :: ComplexData -> SomeResult someFun (force -> !arg) = {- 'arg' will be fully evaluated -}
Another useful application is to combine force
with
evaluate
in order to force deep evaluation
relative to other IO
operations:
import Control.Exception (evaluate) import Control.DeepSeq main = do result <- evaluate $ force $ pureComputation {- 'result' will be fully evaluated at this point -} return ()
Finally, here's an exception safe variant of the readFile'
example:
readFile' :: FilePath -> IO String readFile' fn = bracket (openFile fn ReadMode) hClose $ \h -> evaluate . force =<< hGetContents h
Since: deepseq-1.2.0.0
($!!) :: NFData a => (a -> b) -> a -> b infixr 0 #
the deep analogue of $!
. In the expression f $!! x
, x
is
fully evaluated before the function f
is applied to it.
Since: deepseq-1.2.0.0
(<$!!>) :: (Monad m, NFData b) => (a -> b) -> m a -> m b infixl 4 #
Deeply strict version of <$>
.
Since: deepseq-1.4.3.0
class NFData1 (f :: * -> *) where #
A class of functors that can be fully evaluated.
Since: deepseq-1.4.3.0
Instances
NFData1 [] | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Maybe | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Ratio | Available on Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Ptr | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 FunPtr | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 IORef | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Fixed | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Min | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Max | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 First | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Last | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 WrappedMonoid | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq liftRnf :: (a -> ()) -> WrappedMonoid a -> () # | |
NFData1 Option | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 StableName | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq liftRnf :: (a -> ()) -> StableName a -> () # | |
NFData1 ZipList | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Identity | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 First | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Last | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Dual | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Sum | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Product | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 Down | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 MVar | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 NonEmpty | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData a => NFData1 (Either a) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData a => NFData1 ((,) a) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData a => NFData1 (Array a) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData a => NFData1 (Arg a) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 (Proxy :: * -> *) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 (STRef s) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2) => NFData1 ((,,) a1 a2) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData a => NFData1 (Const a :: * -> *) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 ((:~:) a) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3) => NFData1 ((,,,) a1 a2 a3) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData1 f, NFData1 g) => NFData1 (Product f g) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData1 f, NFData1 g) => NFData1 (Sum f g) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData1 ((:~~:) a :: * -> *) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4) => NFData1 ((,,,,) a1 a2 a3 a4) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData1 f, NFData1 g) => NFData1 (Compose f g) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5) => NFData1 ((,,,,,) a1 a2 a3 a4 a5) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6) => NFData1 ((,,,,,,) a1 a2 a3 a4 a5 a6) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7) => NFData1 ((,,,,,,,) a1 a2 a3 a4 a5 a6 a7) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7, NFData a8) => NFData1 ((,,,,,,,,) a1 a2 a3 a4 a5 a6 a7 a8) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq |
rnf1 :: (NFData1 f, NFData a) => f a -> () #
Lift the standard rnf
function through the type constructor.
Since: deepseq-1.4.3.0
class NFData2 (p :: * -> * -> *) where #
A class of bifunctors that can be fully evaluated.
Since: deepseq-1.4.3.0
Instances
NFData2 Either | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData2 (,) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData2 Array | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData2 Arg | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData2 STRef | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData a1 => NFData2 ((,,) a1) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData2 (Const :: * -> * -> *) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData2 ((:~:) :: * -> * -> *) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2) => NFData2 ((,,,) a1 a2) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
NFData2 ((:~~:) :: * -> * -> *) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3) => NFData2 ((,,,,) a1 a2 a3) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4) => NFData2 ((,,,,,) a1 a2 a3 a4) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5) => NFData2 ((,,,,,,) a1 a2 a3 a4 a5) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6) => NFData2 ((,,,,,,,) a1 a2 a3 a4 a5 a6) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq | |
(NFData a1, NFData a2, NFData a3, NFData a4, NFData a5, NFData a6, NFData a7) => NFData2 ((,,,,,,,,) a1 a2 a3 a4 a5 a6 a7) | Since: deepseq-1.4.3.0 |
Defined in Control.DeepSeq |
rnf2 :: (NFData2 p, NFData a, NFData b) => p a b -> () #
Lift the standard rnf
function through the type constructor.
Since: deepseq-1.4.3.0
Evaluation strategies
Eval
is a Monad that makes it easier to define parallel
strategies. It is a strict identity monad: that is, in
m >>= f
m
is evaluated before the result is passed to f
.
instance Monad Eval where return = Done m >>= k = case m of Done x -> k x
If you wanted to construct a Strategy
for a pair that sparked the
first component in parallel and then evaluated the second
component, you could write
myStrat :: Strategy (a,b) myStrat (a,b) = do { a' <- rpar a; b' <- rseq b; return (a',b') }
Alternatively, you could write this more compactly using the Applicative style as
myStrat (a,b) = (,) <$> rpar a <*> rseq b
Instances
Monad Eval | |
Functor Eval | |
MonadFix Eval | |
Defined in Control.Parallel.Strategies | |
Applicative Eval | |
type Strategy a = a -> Eval a #
A Strategy
is a function that embodies a parallel evaluation strategy.
The function traverses (parts of) its argument, evaluating subexpressions
in parallel or in sequence.
A Strategy
may do an arbitrary amount of evaluation of its
argument, but should not return a value different from the one it
was passed.
Parallel computations may be discarded by the runtime system if the
program no longer requires their result, which is why a Strategy
function returns a new value equivalent to the old value. The
intention is that the program applies the Strategy
to a
structure, and then uses the returned value, discarding the old
value. This idiom is expressed by the using
function.
using :: a -> Strategy a -> a infixl 0 #
Evaluate a value using the given Strategy
.
x `using` s = runEval (s x)
withStrategy :: Strategy a -> a -> a #
dot :: Strategy a -> Strategy a -> Strategy a infixr 9 #
Compose two strategies sequentially. This is the analogue to function composition on strategies.
For any strategies strat1
, strat2
, and strat3
,
(strat1 `dot` strat2) `dot` strat3 == strat1 `dot` (strat2 `dot` strat3) strat1 `dot` strat1 = strat1 strat1 `dot` r0 == strat1
strat2 `dot` strat1 == strat2 . withStrategy strat1
rseq
evaluates its argument to weak head normal form.
rseq == evalSeq Control.Seq.rseq
rdeepseq :: NFData a => Strategy a #
rdeepseq
fully evaluates its argument.
rdeepseq == evalSeq Control.Seq.rdeepseq
evalTraversable :: Traversable t => Strategy a -> Strategy (t a) #
Evaluate the elements of a traversable data structure according to the given strategy.
evalList :: Strategy a -> Strategy [a] #
Evaluate each element of a list according to the given strategy.
Equivalent to evalTraversable
at the list type.
evalTuple2 :: Strategy a -> Strategy b -> Strategy (a, b) #
evalTuple5 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy (a, b, c, d, e) #
evalTuple6 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy (a, b, c, d, e, f) #
evalTuple7 :: Strategy a -> Strategy b -> Strategy c -> Strategy d -> Strategy e -> Strategy f -> Strategy g -> Strategy (a, b, c, d, e, f, g) #