I want to write functions and put result to string.
I want function:
read' :: FilePath -> String
I use:
:t readFile
readFile :: FilePath -> IO String
I make:
read' :: IO ()
read' = do
str <- readFile "/home/shk/workspace/src/test.txt"
putStrLn str
I want to ask str is string or not?
We know that:
:t putStrLn
putStrLn :: String -> IO ()
Then why i can't:
read' :: String
read' = do
str <- readFile "/home/shk/workspace/lxmpp/src/test.txt"
str
I get error that:
Couldn't match expected type `[t0]' with actual type `IO String'
In the return type of a call of `readFile'
In a stmt of a 'do' expression:
str <- readFile "/home/shk/workspace/lxmpp/src/test.txt"
In the expression:
do { str <- readFile "/home/shk/workspace/src/test.txt";
str }
Thank you.
I think no one has answered this, very important question, yet:
I will try to.
The type of the variable
str
isString
, yes. However, the scope of this variable is very limited. I think desugaring the do-notation is necessary for understanding:I think here it becomes more clear why
str
is not good enough. It is an argument of the function you pass to>>=
. Its value only becomes available when someone calls your function, which happens only when theIO
action containing it is being executed.Also, the type of
read' :: IO ()
is determined not so much by theputStrLn str
, but rather by the return type of the operator>>=
. Have a look at it (specialized to theIO
monad):You can see that the result is always an
IO b
action, so trying to change any of arguments won't help.You can read some monad tutorial if you want to understand why the type is the way it is. The intuition behind it is: you can't perform an action without performing an action.
And on the practical side of the question, to use the value returned by some action, instead of trying to do
use (extractValue inputAction)
, which does not make sense becauseextractValue
is not possible, tryinputAction >>= use
if youruse
does involve I/O, orfmap use inputAction
if it does not.You should use
return str
inread'
if you want it to returnstr
instead of()
. You can't stripIO
from the type ofread'
, since it's not a pure function. To get a better grip on how input/output in Haskell works I recommend you to read a tutorial.Just to quibble a bit more, while the other answers are perfectly correct, I want to emphasize something: Something with the type
IO String
isn't just a string that the type system won't let you get at directly. It's a computation that performs I/O to get a string for you. ApplyingreadFile
to a file path doesn't return aString
value any more than putting a steak next to a meat grinder magically turns them into a hamburger.When you have some code like this:
That doesn't mean you're "taking the string out of
getStr
twice". It means you're performing the computation twice and can easily get different results between the two.As a more detailed reason why: It allows impurity.
You absolutely can not perform IO during a pure operation, or it would completely break referential transparency. Technically you can use
unsafePerformIO
but it would break referential transparency in this case - you should only use that if you can guarantee that the result is always the same.