Existe uma maneira geral de 'expandir' uma lista para ser usada como argumentos individuais para outra função?


9

Por exemplo, digamos que eu tenha uma lista de strings L, talvez de um &restargumento. O que posso fazer para Lter o mesmo efeito que o seguinte?

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

(Eu sei mapconcatque funcionaria aqui para este exemplo, mas estou procurando um processo geral.)

Respostas:



6

O que você queria fazer era dobrar ou desdobrar uma sequência de objetos do mesmo tipo. É tentador usar applypara esse fim, porque em muitos casos realmente funcionará. Mas não é exatamente a ferramenta certa para isso, e aqui está o porquê:

  1. applyé um mecanismo de metaprogramação, não apenas isso, também é muito geral para a tarefa, pois pode lidar com seqüências de objetos de tipos diferentes, não necessariamente chamando funções de dois argumentos. Como consequência, algumas vezes você obtém um comportamento incorreto, por exemplo:

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

    Mas, intuitivamente, você esperaria uma incompatibilidade de tipo aqui.

  2. Não há como garantir applyque seja possível processar o máximo de argumentos que você puder fornecer; normalmente é um limite imposto pela implementação do idioma.

  3. A função chamada por applypoderá obter uma referência da lista de argumentos passada a ela dessa maneira. Isso também não é óbvio e pode levar a erros mais tarde:

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

    Se a lista de argumentos for copiada, você pagará o preço de consumir mais memória do que o necessário, mas se não for copiada (passada como está), corre o risco de estragar a lista, se a função chamada modificá-la.


Então, a melhor maneira de fazer isso é usar cl-reduce. O benefício é que ele foi projetado especificamente para executar esse tipo de tarefa.

(cl-reduce 'concat '("foo" "bar" "baz"))
> "foobarbaz"
Ao utilizar nosso site, você reconhece que leu e compreendeu nossa Política de Cookies e nossa Política de Privacidade.
Licensed under cc by-sa 3.0 with attribution required.