For new students, I would show them examples like Eli and Matthias did. For production work, I usually build up strings using string ports.

Compared to various ways of building lists and doing "string-append", or to simply doing lots of incremental "string-append" or "format", using a string port usually permits more tail calls, and sometimes reduces allocations or otherwise inefficient calls. (Note that I assume that the string port implementation itself is very efficient internally.)

For example, a first attempt using string ports, without performance tuning:

(define (alist->string alist)
 (if (null? alist)
     ""
     (let ((os (open-output-string)))
       (let loop ((alist alist))
         (write      (caar alist) os)
         (write-char #\=          os)
         (write      (cdar alist) os)
         (if (null? (cdr alist))
             (begin0 (get-output-string os)
               (close-output-port os))
             (begin (write-char #\space os)
                    (loop (cdr alist))))))))

The string ports example is a lot more verbose than Matthias's string-join/map/format example, but in a couple quick profiles of 100,000 iterations just now, on an alist of only 5 elements, the string ports example ran in 74%-76% of the time. In a couple additional profiles, this performance edge seems to increase with the length of the alist and/or length of the output string.

For programs that are sufficiently fast, this particular performance edge is insignificant. But when you're building large production systems, I've seen attention to grungy low-level performance details in Racket result in boosts of 2x, 10x, 50x... That makes a big difference when you want your Web site to respond in a fraction of a second under load or you're buying/renting application servers.

--
http://www.neilvandyke.org/
_________________________________________________
 For list-related administrative tasks:
 http://lists.racket-lang.org/listinfo/users

Reply via email to