[Haskell-cafe] To seq or not to seq, that is the question

Albert Y. C. Lai trebla at vex.net
Sun Mar 10 21:56:00 CET 2013


On 13-03-08 11:53 PM, Edward Z. Yang wrote:
> Are these equivalent? If not, under what circumstances are they not
> equivalent? When should you use each?
>
>      evaluate a >> return b
>      a `seq` return b
>      return (a `seq` b)

Let a = div 0 0
(or whatever pure but problematic expression you like)
b can be the same as a or something else.

First assume IO. The 3rd one is distinguished by

     main = m >> return ()

where m is to be plugged in the 1st, 2nd, or 3rd. During IO execution, 
the 1st and 2nd throw an exception, the 3rd one does not.

The 2nd is distinguished by

     main = evaluate m

During IO execution, the 2nd throws an exception, the 1st and 3rd do 
not. (m `seq` return () should also do the same.)

In practice, we seldom artificially evaluate or seq an IO action like 
that. And so, that distinction between the 1st and 2nd is seldom 
observed. But another difference matters more in practice:

     main = head [] `seq` (a `seq` return b)

Two consecutive seqs is an instance where the impreciseness of imprecise 
exceptions kicks in. The compiler reserves the right to prefer either 
the empty-list exception or the divide-by-0 exception; perhaps even a 
difference choice at a different time. Whereas:

     main = evaluate (head []) >> (evaluate a >> return b)

By virtue of IO's serializing >> (and lack of unsafeInterleaveIO hehe), 
the exception thrown must be the empty-list one.

If the monad is not IO, then we cannot discuss evaluate. But we can be 
sure that different monads behave differently, and the difference 
involves >>=. Example:

import Control.Monad.State.Strict
a = div 0 0
b = whatever you like
main = print (evalState ((a `seq` return b) >> return ()) ())
-- throws an exception

import Control.Monad.State.Lazy
a = div 0 0
b = whatever you like
main = print (evalState ((a `seq` return b) >> return ()) ())
-- does not throw an exception

(Did you know: Control.Monad.State refers to the Lazy one.)

I leave the rest of the questions unanswered. Enough mind-bending for 
today! :)



More information about the Haskell-Cafe mailing list