プログレスバーをテキストで表示する関数
プログレスバーをテキストで表示する関数を作ってみました。getProgressBarを呼ぶと関数が返ってきて、その関数に現在の進捗を与えるとプログレスバーを表示します。時刻に関連するIOは、getProgressBarの中で閉じるようにしています。
module Main (main) where import Control.Concurrent (threadDelay) import System.IO (stderr) import System.Random (getStdGen, randomRs) import System.Time (getClockTime, diffClockTimes, ClockTime, tdYear, tdMonth, tdHour, tdMin, tdSec) import Text.Printf (printf, hPrintf) getProgressBar :: String -> Int -> IO (Int -> IO ()) getProgressBar title total = return . f =<< getClockTime where f start n | n > total = f' start 100 >> putStrLn "" | otherwise = f' start $ n * 100 `div` total f' :: ClockTime -> Int -> IO () f' start percent = do now <- getClockTime hPrintf stderr "\r%-15s %3d%% |%s| Time: %s" title percent bar $ time now where bar = let max = 40 n = percent * max `div` 100 in (replicate n 'o') ++ (replicate (max - n) ' ') time :: ClockTime -> String time now = let elapsed = diffClockTimes now start hour = (tdYear elapsed * 365 * 24) * (tdMonth elapsed * 30) * (tdHour elapsed) min = tdMin elapsed sec = tdSec elapsed in printf "%02d:%02d:%02d" hour min sec main :: IO () main = do pf <- getProgressBar "test:" 200 loop pf 0 . randomRs (1, 20) =<< getStdGen where loop _ _ [] = error "loop: not reach here." loop pf n (x : xs) | n >= 200 = pf n >> return () | otherwise = pf n >> threadDelay (500 * 1000) >> loop pf (n + x) xs
実行例:
$ ./progtest.exe test: 27% |oooooooooo | Time: 00:00:02