[Top][All Lists]

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: new proc for string-fun.scm: `mapconcat'

From: thi
Subject: Re: new proc for string-fun.scm: `mapconcat'
Date: Sat, 10 Feb 2001 01:22:03 -0800

   From: Dirk Herrmann <address@hidden>
   Date: Fri, 9 Feb 2001 12:43:45 +0100 (MET)

   What I don't like about the function is its do-everything-in-one-step
   nature.  The disadvantage shows in the fact that most of the time in your
   examples you are using 'id' as the function that is to be applied.  This
   is unnecessary and will slow down the computation. (OK, an optimizing
   compiler would be able to get rid of unnecessary stuff, but currently we
   don't have one.)

i wouldn't draw too many conclusions from simple examples.  on the other
hand, my experience is that this high abstraction is quite useful since
the objects to be concatenated are often the result of a `map' of some
kind anyway.

   I'd prefer a set of the following functions:

   (sequence->list seq)
     - transforms a sequence into a list.
   (obj->string obj)
     - makes a string from every object.
   (append/separator sep string ...)
     - appends the strings with the separator inserted between two
       consecutive strings

   Given these functions, mapconcat is still easy to implement, but the
   flexibility is increased, since in most applications you already know
   about the nature of your parameters.  Thus, you would not need to apply
   sequence->list to lists nor obj->string to strings nor id to everything.
   Moreover, the functions above may also be useful in other contexts, at
   least obj->string is one of my favorites.

aside from the "id to everything" clause, i am in agreement.  probably
it would be most in the spirit of the current (ice-9 string-fun) procs
to write a family of optimized mapconcat procs using these primitives.
however, that seems gross.  at the opposite end of the spectrum, i feel
`obj->string' is too "thin" and `sequence->list' doesn't really belong
in (ice-9 string-fun)... so, how about we just add `append/separator'
for now:

(define-public (string-append/separator separator strings)
  "Concatenate with SEPARATOR the list of STRINGS."
  (let ((rev (reverse strings)))
    (apply string-append
           (let loop ((s (cdr rev))
                      (acc (list (car rev))))
             (if (null? s)
                 (loop (cdr s)
                       (cons (car s)
                             (cons separator acc))))))))

here, i've renamed it to `string-append/separator' and chosen to use a
single arg instead of a "rest" arg w/ the rationale that if i'm willing
to pass individual strings to `string-append/separator', it would be
just as easy to enumerate the separator.  also, having to use `apply' in
the more common case is wrong, IMHO.  here is the new `mapconcat'...

(define-public (mapconcat procedure sequence separator)
  "Apply PROCEDURE to each element of SEQUENCE, and concat the results as
strings.  In between each pair of results, stick in SEPARATOR.  Thus, \" \" as
SEPARATOR results in spaces between the values returned by FUNCTION.  SEQUENCE
may be a list, a vector, a bool-vector, or a string."
   (map (lambda (item)
          (let ((val (procedure item)))
            (cond ((string? val) val)
                  ((char? val) (make-string 1 val))
                  (else (with-output-to-string
                          (lambda () (write val)))))))
        (cond ((list? sequence) sequence)
              ((vector? sequence) (vector->list sequence))
              ((string? sequence) (string->list sequence))
               ;; fixme:ttn -- what is guile's error convention?
               (error "bad sequence type"))))))

this still provides all-in-one generality for programmers who like to
just throw args at procs and get the right result... (and who prefer
abstraction to performance).

of course, all this is probably already available in `format'. :->


reply via email to

[Prev in Thread] Current Thread [Next in Thread]