¿Hay una forma general de 'expandir' una lista para usarla como argumentos individuales para otra función?

9

Por ejemplo, supongamos que tengo una lista de cadenas L, quizás de un &restargumento. ¿Qué puedo hacer para Lque tenga el mismo efecto que el siguiente?

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

(Sé mapconcatque funcionaría aquí para este ejemplo, pero estoy buscando un proceso general).

Sean Allred
fuente

Respuestas:

10
(apply #'concat '("foo" "bar" "baz"))
wasamasa
fuente
1
Literalmente solo pensé en esto! Enlace psíquico
Sean Allred
6

Lo que quería hacer parece doblar o desdoblar una secuencia de objetos del mismo tipo. Es tentador usarlo applypara este propósito, porque en muchos casos sí funcionará. Pero no es exactamente la herramienta adecuada para esto, y esta es la razón:

  1. applyes un mecanismo de metaprogramación, no solo eso, también es demasiado general para la tarea porque puede manejar secuencias de objetos de diferentes tipos, no necesariamente llamando a funciones de dos argumentos. Como consecuencia, algunas veces obtendrá un comportamiento incorrecto, por ejemplo:

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

    Pero intuitivamente, esperaría un desajuste de tipo aquí.

  2. No hay forma de asegurarse de applyque pueda procesar tantos argumentos como pueda, normalmente es un límite impuesto por la implementación del lenguaje.

  3. La función llamada por applypodrá obtener una referencia de la lista de argumentos que se le pasa de esta manera. Esto tampoco es obvio y puede provocar errores más adelante:

    (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)
    

    Si se copia la lista de argumentos, entonces paga el precio de conservar más memoria de la necesaria, pero si no se copia (se pasa como está), corre el riesgo de estropear la lista, si la función que se llama la modifica.


Entonces, la mejor manera de hacerlo es usarlo cl-reduce. El beneficio es que fue diseñado específicamente para hacer este tipo de tareas.

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