Haskell IO (String) and String

I want to write functions and put the result in a string.

I want a function:

read' :: FilePath -> String 

I use:

 :t readFile readFile :: FilePath -> IO String 

I do:

 read' :: IO () read' = do str <- readFile "/home/shk/workspace/src/test.txt" putStrLn str 

I want to ask the string str or not?

We know that:

 :t putStrLn putStrLn :: String -> IO () 

Then why can't I:

 read' :: String read' = do str <- readFile "/home/shk/workspace/lxmpp/src/test.txt" str 

I get an error message:

  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 } 

Thanks.

+7
source share
4 answers

I think no one answered this very important question:

I want to ask the string str or not?

I will try to.

The variable type str is String , yes. However, the scope of this variable is very limited. I think that for understanding it is necessary to discourage o-notation:

 read' = readFile "/home/shk/workspace/src/test.txt" >>= (\str -> putStrLn str) 

I think it makes sense here why str not good enough. This is an argument to the function you pass >>= . Its value becomes available only when someone calls your function, which happens only when an IO action containing it is performed.

In addition, the type read' :: IO () is determined not so much by putStrLn str as by the return type of the >>= operator. Take a look at it (specializes in monad IO ):

 (>>=) :: IO a -> (a -> IO b) -> IO b 

You can see that the result is always the IO b action, so trying to change any of the arguments will not help.

You can read the monad tutorial if you want to understand why the type is what it is. The intuition is this: you cannot perform an action without performing an action.

And from the practical side of the question, using the value returned by some action, instead of trying to use (extractValue inputAction) , which makes no sense because extractValue not possible, try inputAction >>= use if your use includes I / O or fmap use inputAction if it is not.

+6
source

Just to come up a little while the other answers are completely correct, I want to emphasize something: something with an IO String type is not just a string that the type system will not let you get directly. This is a calculation that does I / O to get a string for you. Applying readFile to the file path does not return a String value more than putting a steak next to a meat grinder, magically turning them into a hamburger.

When you have a code like this:

 foo = do let getStr = readFile "input.txt" s1 <- getStr s2 <- getStr -- etc. 

This does not mean that you "take the string out of getStr twice." This means that you perform the calculation twice and can easily get different results between them.

+10
source

You should use return str in read' if you want it to return str instead of () . You cannot cut IO from read' type, as this is not a pure function. To better understand how Haskell I / O works, I recommend you read the tutorial .

+4
source

As a more detailed reason why: It allows impurities.

You absolutely cannot perform IO during a clean operation, otherwise it will completely break link transparency. Technically, you can use unsafePerformIO , but in this case it will break link transparency - you should use this only if you can guarantee that the result is always the same.

+1
source