Hello,
several mails spoke about converting an IO String to a String. I have to point
out that such a conversion is not what happens when you use monadic I/O. In
fact, such a conversion is just not possible in Haskell 98.
Since Haskell is a pure language, evaluating a String expression mustn't cause
any side effects. Therefore, if we want to have an operation with side
effects, we cannot have an expression of type String. Instead we use an
expression of type IO String and we mustn't be able to convert an IO String
into a String because, otherwise, we could construct a String expression for
the I/O operation using this conversion facility.
As the nameless guy pointed out, a value of IO String denotes an I/O operation
which has a String as its result. To use this result, you have to combine
your I/O operation with a function that has String parameter and returns an
I/O operation. The result of this combination is an I/O operation which
consists of executing the operation returning the String, applying the
function to it and execution the resulting I/O operation.
I want to explain this with the readFile/putStrLn example. readFile has the
type String -> IO String. Strictly speaking, this does not mean that readFile
is an I/O operation which has a String argument and a String result. It means
that it is a function which can be applied to String values and has
(different) I/O operations for different arguments as its result. Each of
these I/O operations is a file reading operation for one specific path name.
If we apply readFile to the string "test.dat", we get an operation which reads
and returns the content from the respective file. This operation has the type
IO String.
putStrLn has the type String -> IO (). Applying this function to a String
value results in an I/O operation which puts the string to the standard
output and a newline after it. Every I/O operation has to have exactly one
result value. Since putting a line has no meaningful result, the type () is
used as the result type. The type () is a type which has (apart from _|_
which denotes undefindness) the value () as its only value.
Now, having readFile "test.dat" and putStrLn, we can combine these two using
the monadic bind operator >>=. Specialized for I/O operations, this operator
has the type IO a -> (a -> IO b) -> IO b. Specialized for our example it has
the type IO String -> (String -> IO ()) -> IO (). So we are able to write
readFile "test.dat" >>= putStrLn
and get a value of type IO (). This is an I/O operation which first reads the
content from "test.dat", applies putStrLn to it which results in an I/O
operation outputting the file content, and finally executes this I/O
operation so that the content is written to standard output.
Since putStrLn is equivalent to \content -> putStrLn content, we can achieve
the same effect by writing
readFile "test.dat" >>= \content -> putStrLn content.
Using the syntactic sugar of the do notation, we get the equivalent expression
do
content <- readFile "test.dat"
putStrLn content
which looks quiet like imperative programming but isn't really this.
The most important point is the impossibility of an IO a to a conversion. Once
you have an I/O computation you have to use the >>= operator to make its
result available to other parts of your program. You cannot make it available
by conversion. On the top level, every haskell program has a variable called
main which is of type IO (). All a Haskell program does, is executing this
I/O operation and this way all your I/O actions can finally get executed.
Yours, Wolfgang
_______________________________________________
Haskell mailing list
[EMAIL PROTECTED]
http://www.haskell.org/mailman/listinfo/haskell