Edward Z. Yang | 9 Mar 05:53 2013
Picon

To seq or not to seq, that is the question

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)

Furthermore, consider:

    - Does the answer change when a = b? In such a case, is 'return $! b' permissible?
    - What about when b = () (e.g. unit)?
    - What about when 'return b' is some arbitrary monadic value?
    - Does the underlying monad (e.g. if it is IO) make a difference?
    - What if you use pseq instead of seq?

In http://hackage.haskell.org/trac/ghc/ticket/5129 we a bug in
'evaluate' deriving precisely from this confusion.  Unfortunately, the
insights from this conversation were never distilled into a widely
publicized set of guidelines... largely because we never really figured
out was going on! The purpose of this thread is to figure out what is
really going on here, and develop a concrete set of guidelines which we
can disseminate widely.  Here is one strawman answer (which is too
complicated to use in practice):

    - Use 'evaluate' when you mean to say, "Evaluate this thunk to HNF
      before doing any other IO actions, please."  Use it as much as
      possible in IO.

    - Use 'return (a `seq` b)' for strictness concerns that have no
      relation to the monad.  It avoids unnecessary strictness when the
(Continue reading)

Tom Ellis | 9 Mar 09:34 2013
Picon

Re: To seq or not to seq, that is the question

On Fri, Mar 08, 2013 at 08:53:15PM -0800, 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
[...]
>     - Use 'evaluate' when you mean to say, "Evaluate this thunk to HNF
>       before doing any other IO actions, please."  Use it as much as
>       possible in IO.

I've never looked at evaluate before but I've just found it's haddock and
given it some thought.

    http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Exception-Base.html#v:evaluate

Since it is asserted that

    evaluate x = (return $! x) >>= return

is it right to say (on an informal level at least) that evaluating an IO
action to WHNF means evaluating it to the outermost >>= or return?

> For non-IO monads, since everything is imprecise anyway, it doesn't
> matter.

Could you explain what you mean by "imprecise"?

Tom
Edward Z. Yang | 10 Mar 01:39 2013
Picon

Re: To seq or not to seq, that is the question

Excerpts from Tom Ellis's message of Sat Mar 09 00:34:41 -0800 2013:
> I've never looked at evaluate before but I've just found it's haddock and
> given it some thought.
> 
>     http://hackage.haskell.org/packages/archive/base/latest/doc/html/Control-Exception-Base.html#v:evaluate
> 
> Since it is asserted that
> 
>     evaluate x = (return $! x) >>= return
> 
> is it right to say (on an informal level at least) that evaluating an IO
> action to WHNF means evaluating it to the outermost >>= or return?

Sure.

Prelude> let x = undefined :: IO a
Prelude> x `seq` ()
*** Exception: Prelude.undefined
Prelude> (x >>= undefined) `seq` ()
()

> > For non-IO monads, since everything is imprecise anyway, it doesn't
> > matter.
> 
> Could you explain what you mean by "imprecise"?

Imprecise as in imprecise exceptions, http://research.microsoft.com/en-us/um/people/simonpj/papers/imprecise-exn.htm

Edward
(Continue reading)

Albert Y. C. Lai | 10 Mar 21:56 2013
Picon

Re: To seq or not to seq, that is the question

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:

(Continue reading)

Tom Ellis | 22 Mar 11:32 2013
Picon

Re: To seq or not to seq, that is the question

On Fri, Mar 08, 2013 at 08:53:15PM -0800, 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)
> 
> Furthermore, consider:
[...]
>     - Does the underlying monad (e.g. if it is IO) make a difference?
[...]

Here's a monad transformer DelayT which adds an "evaluate" operation to any
monad.  Perhaps it will help in understanding the situation.

(NB it only has the desired behaviour for monads which must force x to at
least WHNF before they can perform the action associated with x >>= f, so
Identity won't do, for example).

% cat evaluate.hs && ghc -fforce-recomp evaluate.hs && ./evaluate
import Control.Monad.Trans.Class (lift, MonadTrans)

data DelayT m a = DelayT (m a) deriving Show

unlift :: DelayT m a -> m a
unlift (DelayT x) = x

instance Monad m => Monad (DelayT m) where
        return = lift . return
(Continue reading)


Gmane