As an impatient person, I typically use progress bars for any code that takes more than a few minutes to run. In a previous post, I wrote about creating ASCII progress bars in R and Racket. The Racket version depended on the `raart` module, which "provides an algebraic model of ASCII that can be used for art, user interfaces, and diagrams." Because I'm not aware of any such library for Chez Scheme , I was left feeling stuck.

Eventually, I found the correct combination of search terms and learned that the solution is simple . The carriage return (`\r`) resets the cursor to the beginning of the line of output and allows for overwriting the previous content, which creates the animated effect of a progress bar advancing .

Armed with this new knowledge, I modified my old Racket code to make a progress bar that works in Chez Scheme and Racket. In the old Racket code, I wrote inflexible procedures that required the user to provide percent progress as an integer. We will relax that requirement and provide an option to change the width of the progress bar.

The first step is to write a procedure that will generate the text for a single iteration of the progress bar.

``````;; tick doesn't mean iteration here
;; it means number of symbols displayed on progress bar
(define (generate-bar tick percent total-width)
(let ([num-equals (if (= tick 0) 0 (- tick 1))]
[arrow (if (= tick 0) "" ">")]
[width (- total-width 6)]
[places-string
(cond
[(< percent 10) "  "]
[(< percent 100) " "]
[else ""])])
(string-append
"["
(make-string num-equals #\=)
arrow
(make-string (- width tick) #\-)
"]"
places-string
(number->string percent)
"%")))
``````

`generate-bar` simply draws the inputs without doing any calculations. `total-width` is measured in the number of characters. A `tick` is a single character to indicate completion . The `places-string` keeps the percent completed number at 3 characters so that the total length of the bar doesn't change and distract from the intended animation effect.

``````> (display (generate-bar 8 20 40))
[=======>--------------------------------] 20%
``````

Now, we need a procedure that will draw a new progress bar on every iteration. I'm using `case-lambda` to make the `total-width` argument optional . `case-lambda` matches on the number of arguments to select which branch to follow. In this case, I use recursion for the branch where `total-width` is not specified. At other times, I've used a helper procedure that contains all the core logic and uses all of the arguments. In that case, `case-lambda` is a wrapper for the helper procedure and is not recursive.

The `progress` procedure does the math to generate the progress bar and uses the carriage return `\r` to overwrite the progress bar on each iteration. We subtract 6 from the `total-width` to account for the characters that are not part of the bar, i.e., `[`, `]`, and `100%`.

``````(define progress
(case-lambda
[(iter max-iter) (progress iter max-iter 80)]
[(iter max-iter total-width)
(let* ([prop (/ iter max-iter)]
[percent (round (* prop 100))]
[tick (round (* prop (- total-width 6)))])
(display (string-append "\r" (generate-bar tick percent total-width))))]))
``````

`use-progress` shows how `progress` can be used in a recursive procedure. The `sleep` procedure in Chez Scheme is not very user friendly. It requires creating a time record of type `time-duration`. `make-time` creates that record from two integer arguments. The first is the number of nanoseconds and the second is the number of seconds. Thus, `(make-time 'time-duration (flonum->fixnum 1e8) 0)` creates a time duration of 0.1 seconds. In Racket, you can write `(sleep 0.1)`. If `sleep` is new to you, it just slows down this loop so that you can see the progress bar advancing. You wouldn't use `sleep` in your actual long-running procedure.

``````(define (use-progress n)
(let loop ([i 0])
(cond [(> i n) (newline)]
[else (progress i n)
(sleep (make-time 'time-duration (flonum->fixnum 1e8) 0))
``````

As an alternative to a progress bar, you could just update a counter. In the example below, if you call `(use-progress-simple 10)`, then the first number in the string, `Rep 0 of 10`, will be incremented in each iteration.

``````(define (use-progress-simple n)
(let ([n-string (number->string n)])
(let loop ([i 0])
(cond [(> i n) (newline)]
[else (display (string-append
"\rRep "
(number->string i)
" of "
n-string))
(sleep (make-time 'time-duration (flonum->fixnum 1e8) 0))
``````

I will leave you with an example of the counter approach in R.

``````use_progress_simple <- function(n){
for (i in 1:n){
cat("\rRep", i, "of", n)
Sys.sleep(0.1)
}
}
``````

 I also made a GUI progress bar for Racket, but Chez Scheme doesn't have easy (any?) GUI capabilities so that was not an option here.

 I subsequently noticed that the carriage return "trick" was included in code for a C++ progress bar, but carriage return was not explicitly mentioned.

 After filling my carriage return knowledge gap, it is clear that the `raart` module was overkill for this simple progress bar.

 I've chosen `=` as the completion character following the style of R's `progress` package.

 I chose 80 as the default `total-width` because that is the default width of the macOS Terminal app. If the `total-width` is wider than your terminal width, then your bar will flow over to the next line and the overwriting will happen on the wrong line.