Strictness is observable

Daniel Fischer wrote:
If you have a strict function, you may evaluate its argument eagerly without changing the result^1, while eager evaluation of a non-strict function's argument may produce _|_ where deferred evaluation wouldn't.
Sadly, that is quite untrue. Strictness is observable, already in Haskell98. That distressing result has nothing to do with imprecise exceptions, seq, non-termination, lack of resources, or the use of unsafe features. Plainly, just by changing the strictness of a function one may cause the program to print different results, such as "strict" or "non-strict" in the code below. -- Haskell98! -- Strictness is observable -- With no seq, no unsafe operations import Control.Exception -- fs and fns are both essentially (const True) functions, -- but differ in strictness fs,fns :: Bool -> Bool -- non-strict fns x = True -- strict fs True = True fs x = True handler :: SomeException -> IO () handler _ = print "strict" test f = handle handler $ if f (error "Bang!") then print "non-strict" else return () main_s = test fs -- prints "strict" main_ns = test fns -- prints "non-strict"

On Friday 01 April 2011 09:00:56, oleg@okmij.org wrote:
Daniel Fischer wrote:
If you have a strict function, you may evaluate its argument eagerly without changing the result^1, while eager evaluation of a non-strict function's argument may produce _|_ where deferred evaluation wouldn't.
Sadly, that is quite untrue. Strictness is observable, already in Haskell98. That distressing result has nothing to do with imprecise exceptions, seq, non-termination, lack of resources, or the use of unsafe features. Plainly, just by changing the strictness of a function one may cause the program to print different results, such as "strict" or "non-strict" in the code below.
John Meacham said it's not Haskell98, I can't be bothered to check the H98 report now, since that's a minor point anyway. So, mea culpa, I didn't consider catch at all, only thought of non-IO code and considered all _|_s equal. I should have made these restrictions explicit, but I wasn't even consciously aware of them.

Then if you turn :
fs True = True
fs x = True
to:
fs x = case x of
True -> True
x' -> True
Is it still strict, or does 'fs' wrap the case test and defer evaluation?
2011/4/1
Daniel Fischer wrote:
If you have a strict function, you may evaluate its argument eagerly without changing the result^1, while eager evaluation of a non-strict function's argument may produce _|_ where deferred evaluation wouldn't.
Sadly, that is quite untrue. Strictness is observable, already in Haskell98. That distressing result has nothing to do with imprecise exceptions, seq, non-termination, lack of resources, or the use of unsafe features. Plainly, just by changing the strictness of a function one may cause the program to print different results, such as "strict" or "non-strict" in the code below.
-- Haskell98! -- Strictness is observable -- With no seq, no unsafe operations
import Control.Exception
-- fs and fns are both essentially (const True) functions, -- but differ in strictness fs,fns :: Bool -> Bool
-- non-strict fns x = True
-- strict fs True = True fs x = True
handler :: SomeException -> IO () handler _ = print "strict"
test f = handle handler $ if f (error "Bang!") then print "non-strict" else return ()
main_s = test fs -- prints "strict"
main_ns = test fns -- prints "non-strict"
_______________________________________________ Haskell-Cafe mailing list Haskell-Cafe@haskell.org http://www.haskell.org/mailman/listinfo/haskell-cafe

On Friday 01 April 2011 10:49:53, Yves Parès wrote:
Then if you turn :
fs True = True fs x = True
to:
fs x = case x of True -> True x' -> True
Is it still strict, or does 'fs' wrap the case test and defer evaluation?
It's still strict, to produce a result, fs has to pattern-match its argument, pattern matching is strict. The report says: "Patterns appear in lambda abstractions, function definitions, pattern bindings, list comprehensions, do expressions, and case expressions. However, the first five of these ultimately translate into case expressions, so defining the semantics of pattern matching for case expressions is sufficient. " So I think the report mandates that both forms are equivalent. You get exactly the same code as for gs :: Bool -> Bool gs x = x `seq` True or hs :: Bool -> Bool hs x = if x then True else True with GHC (with or without optimisations) btw.
participants (3)
-
Daniel Fischer
-
oleg@okmij.org
-
Yves Parès