Re: [Haskell-cafe] Strictness is observable

John Meacham wrote:
Error is not catchable in haskell 98. Only things thrown by raiseIO are.
I see; so GHC, absent any LANGUAGE pragma, should have arranged for `error' to generate a non-catchable exception. Still, Haskell98 specifically allows for the behavior that lets us distinguish strict and non-strict functions (that is, the evaluation order in the pure code). Here is the relevant chapter and the verse from Haskell98 (PDF file found on Haskell.org) 21.2.3 File locking Implementations should enforce as far as possible, at least locally to the Haskell process, multiple- reader single-writer locking on files. That is, there may either be many handles on the same file which manage input, or just one handle on the file which manages output. If any open or semi- closed handle is managing a file for output, no new handle can be allocated for that file. If any open or semi-closed handle is managing a file for input, new handles can only be allocated if they do not manage output. Whether two files are the same is implementation-dependent, but they should normally be the same if they have the same absolute path name and neither has been renamed, for example. Warning: the readFile operation (Section 7.1) holds a semi-closed handle on the file until the entire contents of the file have been consumed. It follows that an attempt to write to a file (using writeFile, for example) that was earlier opened by readFile will usually result in failure with isAlreadyInUseError. The Report specifically warns of the possibility that an implementation that implements file locking, as encouraged by the Report, can distinguish if the entire contents has been consumed or not. The consumption happens in the pure code. Thus the pure Haskell evaluation order starts to matter for a Haskell98-compliant implementation. The following code demonstrates that fact.
-- Haskell98! -- at least as far as GHC implements the absence -- of LANGUAGE pragmas -- Strictness is observable -- With no seq, no unsafe operations
import System.IO 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
-- Any file name that one can create and not be sorry to override file_name = "/tmp/foo"
prepare :: IO () prepare = writeFile file_name "xxx"
{- test f = do h <- openFile file_name ReadMode lst <- hGetContents h >>= return . words ns <- if f (head lst == "") then return "non-strict" else return "" hClose h if lst == [] then print ns else print "strict" -}
handler :: SomeException -> IO () handler _ = print "non-strict"
test f = handle handler $ do h <- openFile file_name ReadMode lst <- hGetContents h ns <- if f (length lst == 0) then return "strict" else return "" writeFile file_name "" print ns
main_s = prepare >> test fs -- prints "strict"
main_ns = prepare >> test fns -- "non-strict"
Yves Pare`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?
Well, we have a test for that, don't we?
fs1 x = case x of True -> True x' -> True
*Main> prepare >> test fs1 "strict"

On Fri, Apr 1, 2011 at 2:23 AM,
John Meacham wrote:
Error is not catchable in haskell 98. Only things thrown by raiseIO are.
I see; so GHC, absent any LANGUAGE pragma, should have arranged for `error' to generate a non-catchable exception.
Actually, it was because you imported Control.Exception. the catch/handle in Control.Exception has different behavior than the catch in Prelude. one catches imprecise exceptions, the other doesn't. John
participants (2)
-
John Meacham
-
oleg@okmij.org