Haskell 控制台中的简单进度指示

Haskell 控制台中的简单进度指示,haskell,progress,Haskell,Progress,在控制台中指示工作进度的最简单方法是什么?输出百分比就足够了,不需要进度条 只使用print会产生很多行,我只想在终端中更改一个字符串。最简单的方法是像wget和其他程序那样:在进度信息之前打印回车和ANSI erase行代码,因此,将光标返回到行的开头并替换现有文本。例如: import Control.Monad import Control.Concurrent import System.IO import Text.Printf putProgress :: String ->

在控制台中指示工作进度的最简单方法是什么?输出百分比就足够了,不需要进度条


只使用
print
会产生很多行,我只想在终端中更改一个字符串。

最简单的方法是像wget和其他程序那样:在进度信息之前打印回车和ANSI erase行代码,因此,将光标返回到行的开头并替换现有文本。例如:

import Control.Monad
import Control.Concurrent
import System.IO
import Text.Printf

putProgress :: String -> IO ()
putProgress s = hPutStr stderr $ "\r\ESC[K" ++ s

drawProgressBar :: Int -> Rational -> String
drawProgressBar width progress =
  "[" ++ replicate bars '=' ++ replicate spaces ' ' ++ "]"
  where bars = round (progress * fromIntegral width)
        spaces = width - bars

drawPercentage :: Rational -> String
drawPercentage progress = printf "%3d%%" (truncate (progress * 100) :: Int)

main :: IO ()
main = do
  forM_ [0..10] $ \i -> do
    let progress = fromIntegral i / 10
    putProgress $ drawProgressBar 40 progress ++ " " ++ drawPercentage progress
    threadDelay 250000
  putProgress "All done."
  hPutChar stderr '\n'
这里的关键是不要打印换行符,这样您就可以在下一次进度更新时返回到换行符的开头


当然,你可以在这里打印出百分比,然后放下条形图,但条形图更酷:)

如果我想要快速脏的东西,我倾向于只打印一系列点。每次有“多一点”的进展,我就写另一个点(没有换行符)。我调整了“一点进展”的度量,使点以每秒一个点的时间刻度出现。不是很复杂,但它显示程序正在做一些事情


如果你真的有某种方法来衡量总的“进度”有多少(我通常没有,但这是你提到的百分比所暗示的),那么你可以将整个程序声明为X点,并在每次取得1/X的进度时打印一个。

另外,你可以使用某种形式的
echo
,它不会打印换行符,因此有一个
返回一个符号擦除
控制字符,因此你可以制作旋转器动画(由-/|制成)。至少可以说,我的Haskell有点生锈,但如果我没记错的话,使用结尾带有\r的putStr将执行回车操作,而不使用换行符,这将使您覆盖您所在的行。@kagali san,Joachim Isaksson,感谢您的酷建议:
sequence\。散布(线程延迟100000)。map(putStr.(“\r”)$cycle“-\\\\\;/”
@Rotsor我发现穿插
threadDelay
会导致输出被吞没。要解决这个问题,我只需将
stdout
替换为
(threadDelay 100000)
(hFlush stdout>>threadDelay 100000)打印到
stderr
而不是
stdout
,这可能是个好主意。您可以自动刷新,并且可以在管道中使用此程序,而不会使进度条出错。@dflemstr:说得好!我已经用一个打印到stderr的更简单的解决方案更新了代码。