3
\$\begingroup\$

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)))))))
\$\endgroup\$
2
\$\begingroup\$

SRFI 13 has string-join. Are you sure you really need to reinvent the wheel?

But since you asked for a review, sure, I'll review.

  1. 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.

  2. 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.

  3. 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))))
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.