简体   繁体   中英

Haskell IO (String) and String

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.

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 . Applying readFile to a file path doesn't return a String 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:

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

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.

I think no one has answered this, very important question, yet:

I want to ask str is string or not?

I will try to.

The type of the variable str is String , yes. However, the scope of this variable is very limited. I think desugaring the do-notation is necessary for understanding:

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

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 the IO action containing it is being executed.

Also, the type of read':: IO () is determined not so much by the putStrLn str , but rather by the return type of the operator >>= . Have a look at it (specialized to the IO monad):

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

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 because extractValue is not possible, try inputAction >>= use if your use does involve I/O, or fmap use inputAction if it does not.

You should use return str in read' if you want it to return str instead of () . You can't strip IO from the type of read' , 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 .

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 .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM