0

I'm trying to understand parallelism in Haskell and one thing that I'm curious about is the signature difference between seq / rseq and par / rpar

seq :: a -> b -> b
par :: a -> b -> b

rseq :: a -> Eval a
rpar :: a -> Eval a

I understand that rseq and rpar are monadic versions so they bear the Eval part. But why aren't seq and par both just a -> a? Kind of like strict identities... A reason for "encomplication" should exist.

There also seems to be a lot of mystery around seq. Some sources say a is evaluated when b is evaluated (to WHNF). Other sources say a is evaluated at call time. It's really confusing! While it's possible to test-drive some things with actual tests I'm afraid I can easily misinterpret the results.

psmears
  • 26,070
  • 4
  • 40
  • 48
Ivan Kleshnin
  • 1,667
  • 2
  • 21
  • 24
  • See [this](http://stackoverflow.com/questions/11046590/the-seq-function-and-strictness) for information on `seq` and why it is a 2-argument-function. – ThreeFx Oct 27 '16 at 10:13

2 Answers2

3

There is already a function of type a -> a that is strict, namely id. Haskell is non-strict, so the only reason a function is called is when you need the result of the function, so when id y is called you need that value. In a similar way, when seq x y is called it's because you need that value.

The operational semantics of seq is not specified in Haskell, which might be why you find it mysterious. And easier function to understand is pseq. The pseq function evaluates its first argument to WHNF and then returns its second argument. The seq function might do the same as pseq, but it might also not. It is defined by its denotational semantics instead (section 6.2 in the Haskell report):

seq ⊥ b = ⊥
seq a b = b, if a /= ⊥

From this we can conclude that seq is strict in both arguments. For strict functions it's quite possible for the caller to evaluate the arguments since this makes no semantic difference. So in a call to seq the caller might evaluate any combination of the arguments in any order.

augustss
  • 22,884
  • 5
  • 56
  • 93
0

To put it short, seq doen not evaluate its argument, it just introduces a dependency between a and b: whenever b is evaluated to WHNF, a is also evaluated.

par does this the same way: whenever b is evaluated a may be evaluated parallelly.

This semantic is the reason why seq a a and hence seq a is useless. Also, allowing seq to directly evaluate a would break the purity.

ThreeFx
  • 7,250
  • 1
  • 27
  • 51
  • Can you elaborate why would evaluation of a thunk break the purity? I believe thunks and values are meant to be interchangeable and the difference is only in operational semantics. And this does not answer why `rpar` and `rseq` are made differently. – Ivan Kleshnin Oct 27 '16 at 10:35
  • 1
    `rseq` and `rpar` create a dependency between the evaluation of the `Eval` value they return and the evaluation of their argument. This works in the context of `Eval`, because `(>>=)` for `Eval` forces evaluation of its first argument before passing a value to its second argument. – Carl Oct 27 '16 at 13:01