par
is declared as:
par :: a -> b -> b
Notice, that argument one is thrown away. In order to use par you need to play tricks like using the same expression multiple times.
If its purpose is to execute a and b in parallel, why wasn't it defined like this?:
par :: (a, b) -> (a, b)
Taking a tuple of (unevaluated) expressions and returning the same expressions - while they are potentially being materialized on background threads.
It seems the latter model is simpler than the former. Why was the design chosen that way?
In the former, you can easily spark more than two computations,
c1 `par` c2 `par` c3 `par` c4 `pseq` something c1 c2 c3 c4
which would be rather cumbersome in the latter.