Search code examples
haskelliomonadsevaluationio-monad

What is the difference between "evaluate" and "return $!"?


Here's an extract from the documentation of evaluate:

Control.Exception.Base.evaluate :: a -> IO a
evaluate x

is not the same as

return $! x

A correct definition is

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

(source)

These seem to have the same meaning. What is the difference between these two definitions?


Solution

  • Quick ref:

    The type of evaluate is:

    evaluate :: a -> IO a
    

    seq has the type a -> b -> b. It firstly evaluates the first argument, then returns the second argument.

    Evaluate follows these three rules:

    evaluate x `seq` y    ==>  y
    evaluate x `catch` f  ==>  (return $! x) `catch` f
    evaluate x >>= f      ==>  (return $! x) >>= f
    

    The difference between the return $! x and (return $! x) >>= return becomes apparent with this expression:

    evaluate undefined `seq` 42
    

    By the first rule, that must evaluate to 42.

    With the return $! x definition, the above expression would cause an undefined exception. This has the value ⊥, which doesn't equal 42.

    With the (return $! x) >>= return definition, it does equal 42.

    Basically, the return $! x form is strict when the IO value is calculated. The other form is only strict when the IO value is run and the value used (using >>=).

    See this mailing list thread for more details.