rpar x = x `par` return x
rseq x = x `pseq` return x
data Eval a = Done a
runEval :: Eval a -> a
runEval (Done x) = x
instance Monad Eval where
return x = Done x
Done x >>= k = k x
You will eventually 'runEval' to extract the evaluated result. This is strict on the monad itself - i.e. you pattern-match against 'Done' in both 'runEval' and in the binding operator (>>=). Therefore, you know that ALL your 'rseq' and 'rpar' statements have finished executing before you get past 'runEval'.
Without use of a monad, this is a bit more difficult - i.e. a use of 'par' might be buried deep in some lazy evaluation, unless you're very careful.