[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