brokenix, pseq combinator is used for sequencing; informally, it eval-
uates its first argument to weak-head normal form, and then eval-
uates its second argument, returning the value of its second argu-
ment. Consider this definition of parMap:
parMap f [] = []
parMap f (x:xs) = y ‘par‘ (ys ‘pseq‘ y:ys)
where y = f x
ys = parMap f xs
The intention here is to spark the evaluation of f x, and then
evaluate parMap f xs, before returning the new list y:ys. The
programmer is hoping to express an ordering of the evaluation: first
spark y, then evaluate ys.
The obvious question is this: why not use #Haskell’s built-in seq
operator instead of pseq? The only guarantee made by seq is that
it is strict in both arguments; that is, seq a ⊥ = ⊥ and seq ⊥
a = ⊥. But this semantic property makes no operational guaran-
tee about order of evaluation. An implementation could impose this
operational guarantee on seq, but that turns out to limit the optimi-
sations that can be applied when the programmer only cares about
the semantic behaviour. Instead, we provide both pseq and seq
(with and without an order-of-evaluation guarantee), to allow the
programmer to say what she wants while leaving the compiler with
as much scope for optimisation as possible.
https://simonmar.github.io/bib/papers/multicore-ghc.pdf