In the wiki page about timing computations, there is an example for timing a pure computation. The core idea is to use the functions evaluate
, rnf
and seq
to ensure that the desired computation (1 + y
in the example below) is performed between the two calls to getCPUTime
:
time :: (Num t, NFData t) => t -> IO ()
time y = do
start <- getCPUTime
replicateM_ lim $ do
x <- evaluate $ 1 + y
rnf x `seq` return ()
end <- getCPUTime
I would like to clarify the use of the functions evaluate
, rnf
and seq
here.
First, evaluate
evaluates its argument to weak head normal form, but it seems that its other purpose is to deal with exceptions that may happen during evaluation. I'm not exactly sure what would happen without it, but I'm ready to assume that it's needed for exception handling.
Then, rnf
evaluates the value to normal form to make sure that the whole computation happens here and that no unevaluated bits remain in weak head normal form, as a result of the call to evaluate
. This may or may not be what one wants, as discussed here, because the additional evaluation may not be necessary.
Finaly, seq
makes sure that the expression rnf x
is evaluated to weak head normal form before returning return ()
.
To summarize: evaluate
deals with potential exceptions, rnf
evaluates x
deeply to make sure that the whole computation is timed and seq
ensures that rnf x
is evaluated in time.
Here are my questions:
seq
redundant with the call to rnf
which has already evaluated the value to normal form?rnf
with rwhnf
? Then would the 3 calls evaluate
, rwhnf
and seq
be redundant such that I could eliminate the use of the last 2 and be happy with just evaluate
?The call to seq
is not redundant because rnf x
needs to be evaluated (to WHNF) to evaluate x
to NF, and that's seq
's job.
Yes, I believe so: just
evaluate $ 1 + y
return ()
But! If the intention of evaluate
here is to handle exceptions I don't think it works because they can be thrown from rnf x
just as well. And if it isn't, I don't see the benefit over
rnf (1 + y) `seq` return ()
And both force
and evaluate
docs suggest a simpler alternative:
evaluate $ force $ 1 + y
return ()
Maybe that page was written before force
was available? Even so, unless I am missing something,
evaluate $ rnf $ 1 + y
would do the job correctly.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With