Whats the difference between IO String and normal String in Haskell
is there a difference like that from IO String to String
i 开发者_JS百科want to take some String values from a IO.
can anyone tell me about this issue. im clueless
The question is what you want to do with the String
value that your IO String
action is going to result in, when the program is run. You write as if you already have your hands on the string, but you don't.
Or: you write as if you have defined or isolated a string, but you haven't. So far you have defined or isolated an action that returns a string. Individual cases of performing that action will return different strings.
Presumably you are trying to define a more complex action -- something of type IO Blah
-- maybe something of type IO ()
the type of something that can be compiled to an executable. The idea is that in the more complex action, having arrived a String
value by performing an action of the type IO String
-- the action you've so far defined -- the executor of the complex action will go on to do something that depends on just what that value is. This is something represented by a function of the type String -> IO Blah
-- maybe String -> IO ()
Of course, such a function doesn't take IO String
values (i.e. actions that return strings) as arguments, but String
values as arguments. We cannot join them directly.
To get from your action that returns a string -- your IO String
value -- and a 'String -> IO Blah' function, to something new -- an action that returns a blah -- we join them through the function >>=
. Specialized to this case >>=
has the type IO String -> (String -> IO Blah) -> IO Blah
-- it might be IO String -> (String -> IO ()) -> IO ()
So, to take the most trivial example of a pair of such things, consider getLine
and putStrLn
.
getLine
is the action of finding out what string has just been entered -- it has the type IO String
.
You might say that putStrLn
prints a String
value to the screen and then returns to the left margin. But that's superficial: what definite thing is done depends on the specification of a String
value, so it has the type String -> IO()
. Which is to say: putStrLn
doesn't do anything, it is a function that maps strings to things that can be done. So as usual, you can define a value in its range type (actions, i.e. IO ()
's) by following the function sign with a name of something in the domain type (strings, i.e. String
) So the combination putStrLn "Gee whiz"
names a definite action, something of type IO ()
.
ghci
will perform such actions on the fly, so, for any string like "Gee whiz" you can write putStrLn "Gee whiz"
and it will immediately 'perform this action' -- the action of writing "Gee whiz" to the screen and returning to the left margin.
Prelude> putStrLn "Gee whiz"
Gee whiz
Prelude>
Similarly the one-character string, that just has the Unix bell character \BEl
in it, is the string we name with '\BEl':[]
or ['\BEL']
or "\BEL"
. For that string as argument, putStrLn
has an audibly quite different kind of action for a value. We get
Prelude> putStrLn "\BEL"
Prelude>
Here you will hear the Unix bell ring before it returns to the left margin. It's a pretty lame audio program, but there you are. ghci
is performing the action of sounding the Unix bell, the action you named with the words putStrLn "\BEL"
before pressing return.
So anyway getLine
is a value of type IO String
and you want to "take this String value from IO". Of course, it doesn't exist yet, it depends what the user types. But we can consider what the program is to do with such a value when it gets it. We can specify this by specifying a function from strings to actions, like putStrLn
. We can thus define a complete action that 'takes a value' and uses it in a certain way by composing them with >>=
or the do
notation sugar.
The most trivial case would be something like echo
:
echo :: IO ()
echo = getLine >>= putStrLn
or equivalently
echo = getLine >>= (\x -> putStrLn x)
or in do
notation:
echo = do
the_string_i_want_to_take <- getLine
putStrLn the_string_i_want_to_take
or less absurdly:
echo = do
x <- getLine
putStrLn x
Of course, you want to "take the string" and maybe mess with it before finishing.
reverseEcho :: IO ()
reverseEcho = getLine >>= (\x -> putStrLn (reverse x))
or more compactly:
reverseEcho = getLine >>= (putStrLn . reverse)
or in do
notation:
reverseEcho = do
the_string_i_want_to_take <- getLine
putStrLn (reverse the_string_i_want_to_take)
or less absurdly:
reverseEcho = do
x <- getLine
putStrLn (reverse x)
if you want to think of 'reversing the string' as something that is done with the string in between getting and printing, you could write:
reverseEcho = do
the_string_i_want_to_take <- getLine
the_string_after_i_have_processed_it <- return (reverse the_string_i_want_to_take)
putStrLn (the_string_after_i_have_processed_it)
or
reverseEcho = do
x <- getLine
y <- return x
putStrLn y
or equivalently
reverseEcho = (getLine >>= (return . reverse)) >>= putStrLn
Here the parentheses aren't necessary because the precedence levels for .
and >>=
are suitably optimized. But (getLine >>= (return . reverse))
is just another name of an "action that returns a string", a value of IO String
, which is not a string itself. You cant apply a String -> Whatever
function to it directly to get a Whatever
, but you can combine it with a function from strings to actions via >>=
.
Similarly
reverseFileAA :: IO ()
reverseFileAA = readFile "AA.txt" >>= writeFile "reversedAA.txt" . reverse
is the action of writing a file named "reversedAA.txt" with the reverse of the string found in AA.txt
, whatever it is, and might be written
reverseFileAA = do
old_file_contents <- readFile "AA.txt"
new_file_contents <- return (reverse old_file_contents)
writeFile "reversedAA.txt" old_file_contents
An IO String is a String in the IO-Monad. If a function in the IO-Monad returns an IO String, you get the String by doing:
do str <- ioFunc
A function is in the IO-Monad when it needs IO-access and has to return IO types.
精彩评论