| CS 331 Spring 2009 > Additional Lecture Notes for Friday, March 6, 2009 |
Here is a very brief look at file I/O in Haskell. Note that we are not discussing error handling, despite the fact that error handling is a necessity in any real-world file handling.
Haskell’s file I/O functions are in the standard package IO.
import IO
To open a file, use function openFile, which takes a filename (String) and a mode, one of the constants ReadMode, WriteMode, AppendMode, ReadWriteMode. Function openFile returns a handle, which can be used to perform further operations on the file.
The return value of openFile is an I/O action, and so it should be called inside a do block.
printFile fileName = do
h <- openFile fileName ReadMode
lines <- hGetContents h
putStr lines
As in the above example, functions that deal with open files generally have names beginning with “h” (e.g., “hGetContents”). Such a function takes a handle as its first parameter, but otherwise is use like other I/O functions.
Function hGetContents reads the entire contents of a file, and returns it in an IO-wrapped String.
Other h-functions include hGetLine, hGetChar, hPutStr, and hPutStrLn. These take a handle as their first parameter, but otherwise act the same as the corresponding non-h functions.
There are predefined handles: stdin, stdout, stderr. These connect to the same streams as C++ cin, cout, and cerr, respectively. Furthermore, most of the non-h I/O functions can generally be considered as wrappers around the corresponding h-functions with one of the predefined handles as a parameter. For example, the following two lines are equivalent.
putStrLn s hPutStrLn stdout s -- same as previous line
Haskell includes a simple way to define new types, using the keyword “data”.
data IntegerAndBool = IB (Integer, Bool)
This defines a new type IntegerAndBool. Note that the name begins with (indeed, must begin with) an upper-case letter.
A value of this new type contains two pieces of data: an Integer, and a Bool. The IB is there to distinguish a value of type IntegerAndBool from a simple pair.
We create new values of type IntegerAndBool using IB.
x = IB (3, True) -- Has type IntegerAndBool y = (3, True) -- Has type Num a => (a,Bool)
Pattern matching works with our new type.
increment IB (i, b) = IB (i+1, b) getBool IB (i, b) = b
To overload functions, Haskell uses type classes. A type class is a collection of types that share properties and operations. Each such type is called an instance of the class.
For example, one of the simplest type classes is Eq, which is the collection all types whose values can be compared using equality (“==”) and inequality (“/=”).
We cannot simply define “==” for a new type.
IB (i1, b1) == IB (i2, b2) = (i1 == i2) && (b1 == b2) -- DOES NOT COMPILE
While this is the correct syntax for defining an operator, because “==” is a method of class Eq, we must make new type an instance of class Eq for this to work.
instance Eq IntegerAndBool where
IB (i1, b1) == IB (i2, b2) = (i1 == i2) && (b1 == b2)
Now we can compare values of type IntegerAndBool using both “==” and “/=”; the latter is written for us, in the obvious way.
Some other standard type classes:
One of the more interesting type classes is Monad. This is a class for wrappers; wrapped values are legal inside a do block. Thus, IO is an instance of Monad.
List is also an instance of Monad.
listOfPairs = do
a <- [1,2,3]
b <- [10,20,30]
return (a, b)
The above can also be written as a list comprehension.
listOfPairs = [(a,b) | a <- [1,2,3], b <- [10,20,30]]
Thus, list comprehensions are really a special case of monad-based do blocks.
The way all this works is that wrappers in class Monad must define two operations, return and the operator “>>=”.
The above do block actually translates to the following (this is a slight oversimplification).
listOfPairs = [1,2,3] >>=
(\a -> ([10,20,30] >>=
(\b -> return (a,b))))
Similarly, consider the following I/O code.
readWrite = do
s <- getLine
putStrLn s
This translates (again, oversimplified) to the following.
readWrite = getLine >>=
(\s -> putStrLn s)
| CS 331 Spring 2009: Additional Lecture Notes for Friday, March 6, 2009 / Updated: 9 Mar 2009 / Glenn G. Chappell / ffggc@uaf.edu |
|