
On 16/02/2008, Alan Carter
Greetings Haskellers,
I'm still hoping that this is solvable. That the instinctive priorities of production programmers are just different to those of researchers, and in fact it *is* possible to open a file *and* read it, checking *both* error returns, without being driven insane. If so, I sincerely suggest an example or two, like the small but well formed programs in K&R, Stroustrup or Gosling saying things like:
if((fp = fopen(...)) != NULL) { if(fgets(...) != NULL) { printf(...); }
fclose(...) }
Best wishes - and still hoping I'm wrong after all
Alan Carter
Well, first of all, have you read the documentation for System.IO? http://www.haskell.org/ghc/docs/latest/html/libraries/base/System-IO.html That has all the corresponding functions you need. I'm not sure I understand completely how you managed to spend two weeks struggling with this before asking. Two minutes on #haskell, or a quick question about how to open and read a file should have got you a useful response. :) First, I'll write the program in a straightforward, but extremely explicit manner, handling possible errors and managing clean up explicitly. This code is rather verbose, so I'll then show some other less verbose ways to handle things while still maintaining safety. So, the first version: import System.IO import Control.Exception (try) main = do mfh <- try (openFile "myFile" ReadMode) case mfh of Left err -> do putStr "Error opening file for reading: " print err Right fh -> do mline <- try (hGetLine fh) case mline of Left err -> do putStr "Error reading line: " print err hClose fh Right line -> putStrLn ("Read: " ++ line) Okay, so this is hopefully fairly self-explanatory to a C-programmer. The only potentially-confusing part is the function 'try', imported from Control.Exception. What it does is to catch all possible exceptions, and reflect them through the return value of the action. If an exception is thrown, 'try' will catch it, and give us a value of the form (Left e), for e being the exception. If instead, the operation succeeds without an exception, we get a value (Right x), where x is the normal return value of the action. The successive 'case' expressions are used to pattern match on this, and handle the errors by printing out an explanatory message. Some example runs of this program: cale@zaphod:~$ rm myFile cale@zaphod:~$ ./read Error opening file for reading: myFile: openFile: does not exist (No such file or directory) cale@zaphod:~$ touch myFile cale@zaphod:~$ ./read Error reading line: myFile: hGetLine: end of file cale@zaphod:~$ echo "hello" >> myFile cale@zaphod:~$ ./read Read: hello This program actually does more error handling than your example C program, so let's tone it down a bit, and make use of some nice IO operations provided to handle errors and clean things up safely in the event of a failure. import System.IO main = withFile "myFile" ReadMode $ \fh -> do line <- hGetLine fh putStrLn ("Read: " ++ line) The function 'withFile' takes a filename, a mode in which to open the file, and a function, taking a filehandle, and giving an action to be performed with that handle, and wraps that action up inside an exception handler, which ensures that the file handle is safely closed if an exception is thrown. (This doesn't matter much in our small example, but I'm sure you'll appreciate how that's an important thing.) We don't handle the exceptions explicitly in this program, but we still could. There are a host of exception-handling mechanisms in Control.Exception, ranging from simple value-oriented things like try, to more explicit operations for wrapping things in exception handlers, like catch: catch :: IO a -> (Exception -> IO a) -> IO a Or to get more selective: catchJust :: (Exception -> Maybe b) -> IO a -> (b -> IO a) -> IO a Which takes a function that gets to decide whether to handle the exception, and at the same time, transform the exception in some way before passing it on to the exception handler. For more information about exceptions, check out the documentation for Control.Exception here: http://www.haskell.org/ghc/docs/latest/html/libraries/base/Control-Exception... I assure you that Haskell is a very reasonable programming language in which to write safe and correct programs. There are whole companies founded on writing high-assurance software in Haskell. If you have more questions, I would be happy to answer them, either here, or perhaps more comfortably, on IRC, #haskell on irc.freenode.net. It's a very beginner friendly channel, and asking questions there is a great way to learn the language quickly, and find the resources you need. Hope this helps! - Cale