8

For example, say I have a list of strings L, perhaps from an &rest argument. What can I do to L that would have the same effect as the following?

(concat (first L) (second L) ... (last L))

(I know mapconcat would work here for this example, but I'm looking for a general process.)

9
(apply #'concat '("foo" "bar" "baz"))
  • 1
    Literally just thought of this! Psychic link. – Sean Allred May 10 '15 at 17:11
6

What you wanted to do seems like folding or un-folding of a sequence of objects of the same type. It is tempting to use apply for this purpose, because in many cases it will indeed work. But it's not exactly the right tool for this, and here is why:

  1. apply is a meta-programming mechanism, not only that, it is also too general for the task because it can handle sequences of objects of different types, not necessarily calling functions of two arguments. As a consequence, some times you will get an incorrect behaviour, for example:

    (apply 'concat "baz" '("foo" "bar"))
     > "bazfoobar"
    

    But intuitively, you'd expect a type mismatch here.

  2. There is no way to ensure apply will be able to process as many arguments as you can give it, it's typically a limit imposed by the language implementation.

  3. The function called by apply will be able to get a reference of the arguments list passed to it in this way. This is also not obvious, and may lead to errors later:

    (let ((test (list 1 2 3)))
      (cons 
       (apply (lambda (&rest x)
                (prog1 (cl-reduce '+ x) (setcar x 0)))
              test)
       test))
    ;; This behaviour is undefined.  Could end up both ways
    > (6 1 2 3)
    > (6 0 2 3)
    

    If the arguments list is copied, then you pay the price of consing more memory than needed, but if it's not copied (passed as is), then you risk spoiling the list, if the function being called modifies it.


So, the better way of doing it is to use cl-reduce. The benefit is that it was specifically designed to do this kind of tasks.

(cl-reduce 'concat '("foo" "bar" "baz"))
> "foobarbaz"

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.