patternMinor
String Concatenation in Scheme
Viewed 0 times
schemeconcatenationstring
Problem
As plain r5rs is lacking in useful string processing utilities, such as string-split and string-join (I'm using MIT/GNU Scheme), I decided to implement my own. My procedure, string-join, works just fine, but I would like my code to be critiqued by seasoned Schemers, and also find out if there are other, more efficient ways to implement the same thing.
(define string-join
(lambda (ls delim)
(define out (open-output-string))
"Join list of strings together by delim into one string."
(let loop ((ls ls))
(if (null? (cdr ls))
(begin
(display (car ls) out)
(get-output-string out))
(begin
(display (car ls) out)
(display delim out)
(loop (cdr ls)))))))Solution
SRFI 13 has
But since you asked for a review, sure, I'll review.
-
Your docstring is in the wrong place. It should be the second subform of the
-
Your procedure doesn't work if the incoming list of strings is empty. You should probably keep track of whether to print the delimiter based on whether you're printing the first element, not whether the list will end soon.
-
You should use
Putting all these suggestions together, we get (tested on Racket and Guile):
(The code above requires SRFI 1 for
If you want your code to be portable to implementations which don't support docstrings, you can use
string-join. Are you sure you really need to reinvent the wheel?But since you asked for a review, sure, I'll review.
-
Your docstring is in the wrong place. It should be the second subform of the
lambda (after the parameters), not after the internal definitions. If that gives you a syntax error, then your implementation does not support docstrings, and you shouldn't try to shoehorn docstrings into a non-standard location.-
Your procedure doesn't work if the incoming list of strings is empty. You should probably keep track of whether to print the delimiter based on whether you're printing the first element, not whether the list will end soon.
-
You should use
for-each rather than a manual loop; it expresses your intent more clearly.Putting all these suggestions together, we get (tested on Racket and Guile):
(define (string-join ls delim)
"Join list of strings together by delim into one string."
(define out (open-output-string))
(for-each (lambda (delim item)
(display delim out)
(display item out))
(cons "" (circular-list delim))
ls)
(get-output-string out))(The code above requires SRFI 1 for
for-each and circular-list.)If you want your code to be portable to implementations which don't support docstrings, you can use
call-with-output-string to avoid the internal definition:(define (string-join ls delim)
"Join list of strings together by delim into one string."
(call-with-output-string
(lambda (out)
(for-each (lambda (delim item)
(display delim out)
(display item out))
(cons "" (circular-list delim))
ls))))Code Snippets
(define (string-join ls delim)
"Join list of strings together by delim into one string."
(define out (open-output-string))
(for-each (lambda (delim item)
(display delim out)
(display item out))
(cons "" (circular-list delim))
ls)
(get-output-string out))(define (string-join ls delim)
"Join list of strings together by delim into one string."
(call-with-output-string
(lambda (out)
(for-each (lambda (delim item)
(display delim out)
(display item out))
(cons "" (circular-list delim))
ls))))Context
StackExchange Code Review Q#104172, answer score: 3
Revisions (0)
No revisions yet.