[Haskell-cafe] Re: A problem with par and modules
boundaries...
Duncan Coutts
duncan.coutts at worc.ox.ac.uk
Sat May 23 14:51:41 EDT 2009
On Sat, 2009-05-23 at 13:31 -0400, Mario Blažević wrote:
> >>> You could probably see exactly what's happening in
> >>> more detail by going through the Core output.
> >>
> >> Thank you, this advice helped. The Core output indicates
> >> that function `test' evaluates the arguments to
> >> `parallelize' before it calls it. In other words, the
> >> call to `parallelize' is optimized as a strict function
> >> call -- which it is. The problem is that this
> >> optimization evaluates the arguments sequentially.
> >> Compiling with optimizations turned off regains the
> >> parallel execution.
> >>
> >> I guess I will report this as a GHC bug. Or is it a
> >> feature request?
> >
> > As Duncan suggessted, try with GHC head (grab a snapshot). `par` et al
> > are much improved.
>
> I already have, with the snapshot from 21st of April. It behaves the same
> as 6.8.2, except it runs for twice as long.
>
> I'd like to take back a part of what I said before, though: `parallelize' should
> be strict only in its second argument.
parallelize a b = a `par` (b `pseq` (a, b))
GHC infers that strictness of parallelize. It thinks that it is lazy in
both args (you can check this yourself using ghc --show-iface). That's
because the definitions of par and pseq use the function 'lazy':
-- The reason for the strange "lazy" call is that it fools
-- the compiler into thinking that pseq and par are non-strict in
-- their second argument (even if it inlines pseq at the call site).
-- If it thinks pseq is strict in "y", then it often evaluates
-- "y" before "x", which is totally wrong.
pseq x y = x `seq` lazy y
par x y = case (par# x) of { _ -> lazy y }
So GHC thinks that par is lazy in both arguments, while it thinks pseq
is strict in the first and lazy in the second.
> Its strictness in the first argument should be the same as with `par`.
Yes, which it is.
> Even though `parallelize x y' always evaluates both x and y,
Be careful about what you mean. Yes, it starts the evaluation of x in
parallel with y, but that does not mean it is strict in x, as you notice
with your example of undefined below.
> the following test works fine with optimizations even if `parallelize'
> is imported:
>
> main = putStrLn (snd $ parallelize undefined "Hello, World!")
>
> So the function is not strict, and I don't understand why GHC should evaluate the
> arguments before the call.
Right, it's lazy in the first and strict in the second argument. As far
as I can see we have no evidence that is is evaluating anything before
the call.
> Does anybody know of a pragma or another way to make a function *non-strict* even
> if it does always evaluate its argument? In other words, is there a way to
> selectively disable the strictness optimization?
Yes, which is what pseq and par already do.
If there's a bug, we need to reproduce it and report it. I cannot
reproduce it.
Duncan
More information about the Haskell-Cafe
mailing list