Haskell IO(字符串)和字符串

发布于 2024-11-19 07:02:52 字数 954 浏览 2 评论 0原文

我想编写函数并将结果放入字符串。

我想要函数:

read' :: FilePath -> String

我使用:

:t readFile
readFile :: FilePath -> IO String

我制作:

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

我想问 str 是不是字符串?

我们知道:

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

那为什么我不能:

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

我收到错误:

 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 }

谢谢。

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.

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(4

尴尬癌患者 2024-11-26 07:02:52

只是为了多争论一点,虽然其他答案完全正确,但我想强调一点: IO String 类型的东西不仅仅是类型系统不允许您获得的字符串直接在。这是一种执行 I/O 来为您获取字符串的计算。将 readFile 应用于文件路径不会返回 String 值,就像将牛排放在绞肉机旁边会神奇地将它们变成汉堡一样。

当您有这样的代码时:

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

这并不意味着您“从 getStr 中取出字符串两次”。这意味着您要执行两次计算,并且很容易在两次之间得到不同的结果。

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.

你怎么这么可爱啊 2024-11-26 07:02:52

我认为还没有人回答这个非常重要的问题:

我想问str是不是字符串?

我会尽力的。

变量str的类型是String,是的。
然而,这个变量的范围是非常有限的。我认为对 do 符号进行脱糖处理对于理解是必要的:

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

我认为在这里可以更清楚为什么 str 不够好。它是您传递给 >>= 的函数的参数。它的值仅在有人调用您的函数时才可用,而这种情况仅在执行包含它的 IO 操作时发生。

另外,read'::IO () 的类型并不是由 putStrLn str 决定的,而是由运算符 >> 的返回类型决定。 >=。看一下它(专门针对 IO monad):

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

您可以看到结果始终是一个 IO b 操作,因此尝试更改任何参数都不会帮助。

如果您想了解为什么类型是这样的,您可以阅读一些 monad 教程。其背后的直觉是:不执行操作就无法执行操作。

在问题的实际方面,使用某个操作返回的值,而不是尝试使用 (extractValue inputAction) ,这没有意义,因为 extractValue不可能,如果您的 use 确实涉及 I/O,请尝试 inputAction >>= use,如果不涉及 I/O,请尝试 fmap use inputAction

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.

久隐师 2024-11-26 07:02:52

如果您希望它返回 str 而不是 (),则应在 read' 中使用 return str。您无法从 read' 类型中剥离 IO,因为它不是纯函数。为了更好地掌握 Haskell 中输入/输出的工作原理,我建议您阅读教程

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.

人事已非 2024-11-26 07:02:52

更详细的原因是:它允许杂质。

绝对不能在纯操作期间执行 IO,否则会完全破坏引用透明性。从技术上讲,您可以使用 unsafePerformIO,但在这种情况下它会破坏引用透明度 - 仅当您可以保证结果始终相同时才应该使用它。

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.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文