[racket] Super basic question about strings
Dear Racketeers:
Ok, I feel really silly asking this, because I feel like I am missing
something really conceptually basic, but the answer isn't apparent to me
from the examples in the Guide:
What's the right way to programatically build up strings in Racket?
For example, suppose I want to consume an association list like
'((k1 . v1) (k2 . v2) ...)
and produce a string that looks like:
"k1=v1 k2=v2 ..."
My natural instinct is to do something like this:
(define (print-kvs assoc-list)
(if (empty? assoc-list)
""
(let* ([kv (car assoc-list)]
[k (car kv)]
[v (cdr kv)])
(string-append (sprintf "~A=~A " (print-key k) (print-val v))
(print-kvs (cdr assoc-list))))))
(define (sprintf . args)
(let ([s (open-output-string)])
(apply fprintf (cons s args))
(get-output-string s)))
;; where print-key and print-val are left unspecified, but they also
;; build up strings, and might make their own calls to string-append and
;; sprintf
But the fact that there doesn't seem to be anything like sprintf in
Racket (despite the presence of fprintf and printf) is screaming at me
that this is the wrong way to do it. And opening and closing a port
over and over as I walk down a list, just to build up a string, looks to
my untrained intuition like an awfully heavyweight solution to a
lightweight problem. But the alternative -- opening a single string
output port, writing all the output to that port, then calling
get-output-string on it -- seems to force me into a more imperative
style, and it forces me to pass the output port into lower-level
functions (e.g. print-key and print-val). This doesn't feel right
either.
So what am I missing here? Any guidance, even if it's just a pointer to
some documentation I missed, would be greatly appreciated.
Thanks!
Richard