简体   繁体   English

Haskell IO(字符串)和字符串

[英]Haskell IO (String) and String

I want to write functions and put result to string.我想编写函数并将结果放入字符串。

I want function:我想要 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?我想问 str 是不是字符串?

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.再狡辩一点,虽然其他答案完全正确,但我想强调一点: IO String类型的东西不仅仅是类型系统不会让你直接得到的字符串。 It's a computation that performs I/O to get a string for you .它是一种执行 I/O 来为您获取字符串的计算。 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.readFile应用于文件路径不会返回String值,就像将牛排放在绞肉机旁边神奇地将它们变成汉堡包一样。

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".这并不意味着您“将字符串从getStr中取出两次”。 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?我想问 str 是不是字符串?

I will try to.我会试着去。

The type of the variable str is String , yes.变量str的类型是String ,是的。 However, the scope of this variable is very limited.但是,这个变量的 scope 是非常有限的。 I think desugaring the do-notation is necessary for understanding:我认为去除 do-notation 的糖分对于理解是必要的:

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

I think here it becomes more clear why str is not good enough.我认为这里更清楚为什么str不够好。 It is an argument of the function you pass to >>= .这是您传递给>>=的 function 的参数 Its value only becomes available when someone calls your function, which happens only when the IO action containing it is being executed.它的值只有在有人调用您的 function 时才可用,只有在执行包含它的IO操作时才会发生这种情况。

Also, the type of read':: IO () is determined not so much by the putStrLn str , but rather by the return type of the operator >>= .此外, read':: IO ()的类型不是由putStrLn str决定的,而是由运算符的返回类型>>=决定的。 Have a look at it (specialized to the IO monad):看看它(专门用于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.您可以看到结果始终是IO b操作,因此尝试更改任何 arguments 都无济于事。

You can read some monad tutorial if you want to understand why the type is the way it is.如果您想了解类型为何如此,您可以阅读一些 monad 教程。 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.在问题的实际方面,要使用某些操作返回的值,而不是尝试use (extractValue inputAction) ,这没有意义,因为extractValue是不可能的,尝试inputAction >>= use如果您use则使用涉及 I/O,如果不涉及,则fmap use inputAction

You should use return str in read' if you want it to return str instead of () .如果您希望它返回str而不是() ,则应该在read'中使用return str You can't strip IO from the type of read' , since it's not a pure function.您不能从read'类型中删除IO ,因为它不是纯 function。 To get a better grip on how input/output in Haskell works I recommend you to read a tutorial .为了更好地了解 Haskell 中的输入/输出如何工作,我建议您阅读教程

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.您绝对不能在纯操作期间执行 IO ,否则会完全破坏引用透明性。 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 .从技术上讲,您可以使用unsafePerformIO ,但在这种情况下它会破坏参照透明性——您应该只在可以保证结果始终相同的情况下使用它。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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