【问题标题】:putStr and putStrLn messing with the output [duplicate]putStr 和 putStrLn 弄乱了输出[重复]
【发布时间】:2022-01-09 23:56:32
【问题描述】:

我是从《Learn You a Haskell For Great Good》一书中学习 Haskell 的。有这个代码

import Control.Monad
import Data.Char
main = forever $ do
    putStr "Give me some input: "
    l <- getLine
    putStrLn $ map toUpper l

当我最初在 gitbash 中运行此代码时,它只是在给出输入文本并按 Enter 后询问任何输入(假设输入文本是 soham)它显示 Give me some input: SOHAM

然后我将代码更改为

import Control.Monad
import Data.Char
main = forever $ do
    putStrLn "Give me some input: "
    l <- getLine
    putStrLn $ map toUpper l

运行后它显示Give me some input: 并要求输入。在给出相同的输入soham 后,它显示SOHAM

再次将代码更改为

import Control.Monad
import Data.Char
main = forever $ do
    putStr "Give me some input: "
    l <- getLine
    putStr $ map toUpper l

它只是一次又一次地接受输入,当我按下文件结束键(ctrl+C)时,它会并排显示所有输出,但输出就像原始代码一样。

为什么会发生这种变化?

【问题讨论】:

  • 这是由于行缓冲,在putStrLn之前使用hSetBuffering stdout NoBuffering(导入System.IO)。
  • 请删除您的图形,因为它会影响可访问性。而是剪切并粘贴您的输出。谢谢。

标签: haskell io


【解决方案1】:

这可能是由于缓冲:使用LineBuffering,只要输出新行,它就会刷新。因此,这意味着如果您使用putStr,并且字符串本身不包含新行'\n' 字符,它将缓冲输出并等待直到写入新行以实际将输出写入控制台

您可以将其设置为NoBuffering 以立即将内容写入控制台。您可以使用hSetBuffering :: Handle -&gt; BufferMode -&gt; IO () 更改stdout 的缓冲设置:

import Control.Monad
import Data.Char
import System.IO

main = do
  hSetBuffering stdout NoBuffering
  forever $ do
    putStr "Give me some input: "
    l <- getLine
    putStrLn $ map toUpper l

另一种选择是仅使用hFlush :: Handle -&gt; IO () 刷新putStr 的缓冲区,因此不更改缓冲策略本身:

import Control.Monad
import Data.Char
import System.IO

main = do $ forever
  putStr "Give me some input: "
  hFlush stdout
  l <- getLine
  putStrLn $ map toUpper l

【讨论】:

  • “由于缓冲”的意思。我有一个haskell的新手。所以我不知道你在说什么
  • @SohamChatterjee:: 如果您打印到标准输出,它通常不会立即写入,而是等到您写入新行,然后再写入整行(或如果您将其设置为BlockBuffering,甚至是一行行)。通过将缓冲设置为NoBuffering,您可以立即将输出写入控制台。
  • @SohamChatterjee:这实际上与 Haskell 没有太大关系。在 Java 中,通常还会缓冲对控制台的写入,以防止在其上花费大量 I/O 时间。
  • @SohamChatterjee 缓冲对于初学者来说可能很复杂。在许多许多编程语言中,当您打印每个字母时,它不会立即发送到屏幕上。相反,它存储在称为“缓冲区”的内存区域中。一旦缓冲区包含足够的字母,它的全部内容就会被发送到屏幕(用术语“flushed”),清空缓冲区。这种奇怪的机制是为了提高效率:一封一封地发送信件太慢了。打印新行时也会发生刷新:这就是 putStrLn 工作正常的原因。
  • @SohamChatterjee putStr 不会刷新。使用NoBuffering 命令,您可以禁用缓冲区,强制每个字母立即打印到屏幕上。即使逐个打印字母比批量打印字母要慢得多,但对于短输出来说已经足够了。
猜你喜欢
  • 2014-03-18
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2011-05-28
  • 2014-03-04
  • 1970-01-01
  • 2020-01-16
相关资源
最近更新 更多