Re: how to convert IO String to string---- still have questions
Thanks a lot for you guys' help. I am very new to haskell and tried some methods you guys advised, doesn't seem to work, i think i didn't do it properly, here's my code and result, hope you can point out what's wrong. thanks! my code: myReadFile :: IO String myReadFile = readFile "d:/hugs98/input.txt" theString :: String theString = do s <- myReadFile putStrLn s the error message i got in hugs98 ERROR "D:\hugs98\parser.hs":16 - Type error in explicitly typed binding *** Term : theString *** Type : IO () *** Does not match : String
From: Ashley Yakeley <ashley@semantic.org> To: "Ahn Ki-yung" <kyagrd@bawi.org>,"Haskell List" <haskell@haskell.org> Subject: Re: how to convert IO String to string Date: Fri, 22 Nov 2002 15:09:34 -0800
At 2002-11-22 14:49, Ahn Ki-yung wrote:
'do' is a syntactic sugar of monadic operations. The original form can be written as
main = myReadFile >>= \s -> putStrLn s
That's correct. In this case, the 's' has type String. So the IO String has been 'converted' into a String, but only within the context of the IO monad.
I think ultimately everything is syntactic sugar.
-- Ashley Yakeley, Seattle WA
_______________________________________________ Haskell mailing list Haskell@haskell.org http://www.haskell.org/mailman/listinfo/haskell
_________________________________________________________________ Add photos to your messages with MSN 8. Get 2 months FREE*. http://join.msn.com/?page=features/featuredemail
On Sun, 24 Nov 2002 09:05:17 -0900 "Lu Mudong" <mudong@hotmail.com> wrote:
Thanks a lot for you guys' help.
I am very new to haskell and tried some methods you guys advised, doesn't seem to work, i think i didn't do it properly, here's my code and result, hope you can point out what's wrong. thanks!
my code:
myReadFile :: IO String myReadFile = readFile "d:/hugs98/input.txt"
theString :: String theString = do s <- myReadFile putStrLn s
the error message i got in hugs98
ERROR "D:\hugs98\parser.hs":16 - Type error in explicitly typed binding*** Term : theString *** Type : IO () *** Does not match : String
You can convert an IO string to a string, but the resulting string can only be given as an input to a function of type String -> IO <put your favourite type here> This approach is called "monads" and is needed because haskell is a lazy language, so order of evaluation is unspecified, while input/output usually needs a precise order of evaluation. In fact the only way (almost, but don't get confused by now) to execute non-purely-functional code (i/o for example) in haskell is to bind the name "main" to an IO operation. Now consider your "theString" function: it executes myReadFile, which is an IO operation, so theString is an IO operation itselv, and has type "IO ()", since putStrLn has this type. Note that I said "operation". If you think about types like "IO a" as "An IO operation returning the type a" everything will be more clear. Maybe someone has to suggest some simple article on monads. Bye Vincenzo
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
Nick Name wrote:
This approach is called "monads" and is needed because haskell is a lazy language, so order of evaluation is unspecified, while input/output usually needs a precise order of evaluation.
It is needed because Haskell is a functional language, where functions are referentially transparent, so the result of applying a function to an argument depends only upon the function and the argument, and not upon some hidden "state". Even if Haskell were strict, you still wouldn't be able to treat I/O operations as functions without discarding referential transparency.
Maybe someone has to suggest some simple article on monads.
"What the hell are Monads?" http://www.dcs.gla.ac.uk/~nww/Monad.html -- Glynn Clements <glynn.clements@virgin.net>
On Sun, 24 Nov 2002 20:42:31 +0000 Glynn Clements <glynn.clements@virgin.net> wrote:
Even if Haskell were strict, you still wouldn't be able to treat I/O operations as functions without discarding referential transparency.
Yes, but if haskell were strict, it wouldn't really need referential transparency, that's why I mentioned lazyness. Vincenzo -- Fedeli alla linea, anche quando non c'è Quando l'imperatore è malato, quando muore,o è dubbioso, o è perplesso. Fedeli alla linea la linea non c'è. [CCCP]
On Sun, 24 Nov 2002 22:50:43 +0100, Nick Name <nick.name@inwind.it> wrote:
On Sun, 24 Nov 2002 20:42:31 +0000 Glynn Clements <glynn.clements@virgin.net> wrote:
Even if Haskell were strict, you still wouldn't be able to treat I/O operations as functions without discarding referential transparency.
Yes, but if haskell were strict, it wouldn't really need referential transparency, that's why I mentioned lazyness.
Referential transparency is still useful in strict languages. I sometimes use updatable references in ML but find myself having to think very carefully whether what I'm doing is safe. Of course the need is rather greater in lazy languages. Ganesh
--- Lu Mudong <mudong@hotmail.com> wrote:
Thanks a lot for you guys' help.
I am very new to haskell and tried some methods you guys advised, doesn't seem to work, i think i didn't do it properly, here's my code and result, hope you can point out what's wrong. thanks!
Lots of theory, here's some code: -- Begin code module Main() where import IO myReadFile :: String -> IO String myReadFile filename = readFile filename main :: IO () main = do s <- myReadFile "/etc/fstab" let length = doStuffWithNormalString s putStr "Length of File :" putStr (show length) putStr "\n" -- For example, count the number of characters doStuffWithNormalString :: String -> Int doStuffWithNormalString s = length s; -- End code My Explination: Basically, your program starts in a do loop. Anything that returns an IO something needs a <-. For example a <- someIOReturnValue And you can use a as a normal value w/o an IO type. Anything function that doesn't return the IO type needs a let a = someNormalFunction. And you can pretty much do what you want after you know these things. Oh yea, you can't do IO stuff in a non IO function. This is a pretty nasty part of learning haskell, but once you get used to it, you might actually like it. Later, David J. Sankel
participants (6)
-
David Sankel -
Ganesh Sittampalam -
Glynn Clements -
Lu Mudong -
Nick Name -
Wolfgang Jeltsch