problems with working with Handles
Hello, We're two students from the department of computer science at the University of Utrecht (the Netherlands), and we're havind some severe difficulties in working with file handles in Haskell. Consider for example the following program: main = do --let inputfile = "input.txt" let inputtext = "testit" let outputfile = "output.txt" writeFile outputfile "" handle2 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle2 (inputtext ++ " extra") handle3 <- openFileEx outputfile (BinaryMode ReadMode) inputtext2 <- hGetContents handle3 handle4 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle4 (inputtext ++ " extra2") The text which should be in the outputfile is "testit extra extra2", instead "testit extra2" is written in. Another strange problem is with the following program: ------------- main = do putStr "Give inputfile for use of Super encoding\n" inputfile <- getLine handle <- openFileEx inputfile (BinaryMode ReadMode) text <- hGetContents handle putStr "Give outputfile for use of Super encoding\n" outputfile <- getLine encode text outputfile encode :: String -> String -> IO() encode text outputfile = do outputhandle <- openFileEx outputfile (BinaryMode WriteMode) bwt (runlengthEncode text) outputhandle bwthandle <- openFileEx outputfile (BinaryMode ReadMode) bwttext <- hGetContents bwthandle tracer' bwttext mtfhandle <- openFileEx outputfile (BinaryMode WriteMode) hPutStr mtfhandle (arithmeticEncode (runlengthEncode (movetofront bwttext))) tracer' :: String -> IO() tracer' x = writeFile "temp.txt" x ------------- This only seems to work when we're calling 'tracer' ', so if we're actually doing somewhing with "bwttext" before using it... Also, we're wondering when you can close a handle. Personally we thought you could close it if you are "done" with it, yet if you've captured the contents of a file like this: handle <- openFileEx inputfile (BinaryMode ReadMe) text <- hGetContents handle hClose handle putStr text no text appears on the screen; "text" seems empty. We're testing on a Windows machine by the way. Regards, Niels Reyngoud and Richard Nieuwenhuis
I believe this is related to the topic discussed a few weeks ago. See http://haskell.org/pipermail/haskell/2003-May/011851.html and responses. At least, this is most likely the curprit of your second problem. I'm not so sure about the first one. I would expect "testit extratestit extra2" to be the text in the output file. I'm guessing this has something to do with buffering. When you open the files, try 'hSetBuffering h? NoBuffering' and see if that fixes it. -- Hal Daume III | hdaume@isi.edu "Arrest this man, he talks in maths." | www.isi.edu/~hdaume On Thu, 12 Jun 2003, Niels Reyngoud wrote:
Hello,
We're two students from the department of computer science at the University of Utrecht (the Netherlands), and we're havind some severe difficulties in working with file handles in Haskell. Consider for example the following program:
main = do --let inputfile = "input.txt" let inputtext = "testit" let outputfile = "output.txt" writeFile outputfile "" handle2 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle2 (inputtext ++ " extra")
handle3 <- openFileEx outputfile (BinaryMode ReadMode) inputtext2 <- hGetContents handle3 handle4 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle4 (inputtext ++ " extra2")
The text which should be in the outputfile is "testit extra extra2", instead "testit extra2" is written in.
Another strange problem is with the following program:
------------- main = do putStr "Give inputfile for use of Super encoding\n" inputfile <- getLine handle <- openFileEx inputfile (BinaryMode ReadMode) text <- hGetContents handle putStr "Give outputfile for use of Super encoding\n" outputfile <- getLine encode text outputfile
encode :: String -> String -> IO() encode text outputfile = do outputhandle <- openFileEx outputfile (BinaryMode WriteMode) bwt (runlengthEncode text) outputhandle bwthandle <- openFileEx outputfile (BinaryMode ReadMode) bwttext <- hGetContents bwthandle tracer' bwttext mtfhandle <- openFileEx outputfile (BinaryMode WriteMode) hPutStr mtfhandle (arithmeticEncode (runlengthEncode (movetofront bwttext)))
tracer' :: String -> IO() tracer' x = writeFile "temp.txt" x
------------- This only seems to work when we're calling 'tracer' ', so if we're actually doing somewhing with "bwttext" before using it...
Also, we're wondering when you can close a handle. Personally we thought you could close it if you are "done" with it, yet if you've captured the contents of a file like this:
handle <- openFileEx inputfile (BinaryMode ReadMe) text <- hGetContents handle hClose handle putStr text
no text appears on the screen; "text" seems empty.
We're testing on a Windows machine by the way.
Regards, Niels Reyngoud and Richard Nieuwenhuis
_______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
Hello,
We're two students from the department of computer science at the University of Utrecht (the Netherlands), and we're havind some severe difficulties in working with file handles in Haskell. Consider for example the following program:
main = do --let inputfile = "input.txt" let inputtext = "testit" let outputfile = "output.txt" writeFile outputfile "" handle2 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle2 (inputtext ++ " extra")
handle3 <- openFileEx outputfile (BinaryMode ReadMode) inputtext2 <- hGetContents handle3 handle4 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle4 (inputtext ++ " extra2")
The text which should be in the outputfile is "testit extra extra2", instead "testit extra2" is written in.
The contents of output.txt in the filesystem is undefined until you close the handle. And what do you expect to happen with two handles open on the same file for writing? Bad things are going to happen... For your other question, see the previous thread that someone else mentioned. hGetContents is a bit badly behaved, and should only be used in trivial cases. Here you should use hGetLine or hGetChar instead. That way you know where you are in the file, and calling hClose is safe. --KW 8-)
On Thu, 12 Jun 2003, Niels Reyngoud wrote:
Hello,
We're two students from the department of computer science at the University of Utrecht (the Netherlands), and we're havind some severe difficulties in working with file handles in Haskell. Consider for example the following program:
main = do --let inputfile = "input.txt" let inputtext = "testit" let outputfile = "output.txt" writeFile outputfile "" handle2 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle2 (inputtext ++ " extra")
handle3 <- openFileEx outputfile (BinaryMode ReadMode) inputtext2 <- hGetContents handle3 handle4 <- openFileEx outputfile (BinaryMode WriteMode) hPutStr handle4 (inputtext ++ " extra2")
Did you intend `inputtext2` in the line above?
The text which should be in the outputfile is "testit extra extra2", instead "testit extra2" is written in.
Also, beware that you're reopening `outputfile` (to `handle4`) before actually reading the file into `inputtext2`. (`hGetContents` reads lazily.) I wouldn't be surprised if this causes `inputtext2` to be "". Dean
Hello all, Thanks for your replies on our previous posts. To avoid the lazy behaviour, we tried to write our own IO module "IOExts2" which basically redifnes readFile, writeFile and appendFile to make sure they use binary-mode and strict behaviour. The libary is as follows: ---------- module IOExts2(readFile', writeFile', appendFile') where import IO import IOExts readFile' :: String -> IO String readFile' inputfile = do readhandle <- openFileEx inputfile (BinaryMode ReadMode) x <- hGetContents readhandle seq x (return x) {- seq x (do hClose readhandle return x) -} writeFile' :: String -> String -> IO() writeFile' outputfile text = seq text (writeFile'' outputfile text) writeFile'' :: String -> String -> IO() writeFile'' outputfile text = do writehandle <- openFileEx outputfile (BinaryMode WriteMode) hPutStr writehandle text hFlush writehandle hClose writehandle appendFile' :: String -> String -> IO() appendFile' outputfile text = seq text (appendFile'' outputfile text) appendFile'' :: String -> String -> IO() appendFile'' outputfile text = do appendhandle <- openFileEx outputfile (BinaryMode AppendMode) hPutStr appendhandle text hFlush appendhandle hClose appendhandle --------------- Yet, there's still one problem left with readFile'. The handles of appendFile' and writeFile' are properly closed, but when I try to close the handle used for reading (as shown by the parts commented above) and try the following small test, which uses a file "123.txt" that consists of the string "blaat" only a "b" is outputted. When I do not close the handle, the entire string "blaat" is outputted. test = do x <- readFile' "123.txt" putStr x Regards, Niels Reyngoud
On Friday, 2003-06-13, 10:33, CEST, Niels Reyngoud wrote:
[...]
To avoid the lazy behaviour, we tried to write our own IO module "IOExts2" which basically redifnes readFile, writeFile and appendFile to make sure they use binary-mode and strict behaviour. The libary is as follows:
[...]
readFile' :: String -> IO String readFile' inputfile = do readhandle <- openFileEx inputfile (BinaryMode ReadMode) x <- hGetContents readhandle seq x (return x)
Are you sure you want seq and not deepSeq?
[...]
Wolfgang
Niels Reyngoud wrote:
Hello all,
Thanks for your replies on our previous posts. To avoid the lazy behaviour, we tried to write our own IO module "IOExts2" which basically redifnes readFile, writeFile and appendFile to make sure they use binary-mode and strict behaviour. The libary is as follows:
---------- module IOExts2(readFile', writeFile', appendFile') where
import IO import IOExts
readFile' :: String -> IO String readFile' inputfile = do readhandle <- openFileEx inputfile (BinaryMode ReadMode) x <- hGetContents readhandle seq x (return x) {- seq x (do hClose readhandle return x) -}
`seq` guarantees only enough evaluation to determine whether its first argument is bottom. That's why your commented code reads only the first character. You need to evaluate the entire string. As someone else suggested, `deepSeq` is one way to do this. I've appended the current version of my DeepSeq module to this reply.
writeFile' :: String -> String -> IO() writeFile' outputfile text = seq text (writeFile'' outputfile text)
writeFile'' :: String -> String -> IO() writeFile'' outputfile text = do writehandle <- openFileEx outputfile (BinaryMode WriteMode) hPutStr writehandle text hFlush writehandle hClose writehandle
appendFile' :: String -> String -> IO() appendFile' outputfile text = seq text (appendFile'' outputfile text)
appendFile'' :: String -> String -> IO() appendFile'' outputfile text = do appendhandle <- openFileEx outputfile (BinaryMode AppendMode) hPutStr appendhandle text hFlush appendhandle hClose appendhandle
Output is not done lazily, so use of `seq` in the above is superfluous.
---------------
Yet, there's still one problem left with readFile'. The handles of appendFile' and writeFile' are properly closed, but when I try to close the handle used for reading (as shown by the parts commented above) and try the following small test, which uses a file "123.txt" that consists of the string "blaat" only a "b" is outputted. When I do not close the handle, the entire string "blaat" is outputted.
test = do x <- readFile' "123.txt" putStr x
Regards, Niels Reyngoud
DeepSeq.lhs -- deep strict evaluation support The `DeepSeq` class provides a method `deepSeq` that is similar to `seq` except that it forces deep evaluation of its first argument before returning its second argument. Instances of `DeepSeq` are provided for Prelude types. Other instances must be supplied by users of this module. $Id: DeepSeq.lhs,v 1.5 2002/04/01 20:58:24 heringto Exp $
module DeepSeq where
class DeepSeq a where deepSeq :: a -> b -> b
infixr 0 `deepSeq`, $!!
($!!) :: (DeepSeq a) => (a -> b) -> a -> b f $!! x = x `deepSeq` f x
instance DeepSeq () where deepSeq = seq
instance DeepSeq Bool where deepSeq = seq instance DeepSeq Char where deepSeq = seq
instance (DeepSeq a) => DeepSeq (Maybe a) where deepSeq Nothing y = y deepSeq (Just x) y = deepSeq x y
instance (DeepSeq a, DeepSeq b) => DeepSeq (Either a b) where deepSeq (Left a) y = deepSeq a y deepSeq (Right b) y = deepSeq b y
instance DeepSeq Ordering where deepSeq = seq
instance DeepSeq Int where deepSeq = seq instance DeepSeq Integer where deepSeq = seq instance DeepSeq Float where deepSeq = seq instance DeepSeq Double where deepSeq = seq
instance DeepSeq (a -> b) where deepSeq = seq
instance DeepSeq (IO a) where deepSeq = seq
instance (DeepSeq a) => DeepSeq [a] where deepSeq [] y = y deepSeq (x:xs) y = deepSeq x $ deepSeq xs y
instance (DeepSeq a,DeepSeq b) => DeepSeq (a,b) where deepSeq (a,b) y = deepSeq a $ deepSeq b y instance (DeepSeq a,DeepSeq b,DeepSeq c) => DeepSeq (a,b,c) where deepSeq (a,b,c) y = deepSeq a $ deepSeq b $ deepSeq c y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d) => DeepSeq (a,b,c,d) where deepSeq (a,b,c,d) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d,DeepSeq e) => DeepSeq (a,b,c,d,e) where deepSeq (a,b,c,d,e) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d $ deepSeq e y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d,DeepSeq e,DeepSeq f) => DeepSeq (a,b,c,d,e,f) where deepSeq (a,b,c,d,e,f) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d $ deepSeq e $ deepSeq f y instance (DeepSeq a,DeepSeq b,DeepSeq c,DeepSeq d,DeepSeq e,DeepSeq f,DeepSeq g) => DeepSeq (a,b,c,d,e,f,g) where deepSeq (a,b,c,d,e,f,g) y = deepSeq a $ deepSeq b $ deepSeq c $ deepSeq d $ deepSeq e $ deepSeq f $ deepSeq g y
--end--
On Fri, Jun 13, 2003 at 10:34:53AM -0400, Dean Herington wrote:
`seq` guarantees only enough evaluation to determine whether its first argument is bottom. That's why your commented code reads only the first character. You need to evaluate the entire string. As someone else suggested, `deepSeq` is one way to do this. I've appended the current version of my DeepSeq module to this reply.
One can also use Strategies module that comes with GHC (in package concurrent), for example: y `demanding` rnf x will Reduce x to Normal Form, before evaluating y. I hope I got this right :) Best regards, Tom -- .signature: Too many levels of symbolic links
Dnia pią 13. czerwca 2003 16:34, Dean Herington napisał:
`seq` guarantees only enough evaluation to determine whether its first argument is bottom. That's why your commented code reads only the first character. You need to evaluate the entire string. As someone else suggested, `deepSeq` is one way to do this.
There is simpler: foldr seq (return ()) str -- __("< Marcin Kowalczyk \__/ qrczak@knm.org.pl ^^ http://qrnik.knm.org.pl/~qrczak/
participants (7)
-
Dean Herington -
Hal Daume III -
Keith Wansbrough -
Marcin 'Qrczak' Kowalczyk -
Niels Reyngoud -
Tomasz Zielonka -
Wolfgang Jeltsch