Esiste un modo generale per "espandere" un elenco da utilizzare come singoli argomenti in un'altra funzione?


9

Ad esempio, supponiamo che io abbia un elenco di stringhe L, forse da un &restargomento. Cosa posso fare per Lavere lo stesso effetto del seguente?

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

(So mapconcatche funzionerebbe qui per questo esempio, ma sto cercando un processo generale.)

Risposte:



6

Quello che volevi fare sembra piegare o non piegare una sequenza di oggetti dello stesso tipo. È allettante usare applya questo scopo, perché in molti casi funzionerà davvero. Ma non è esattamente lo strumento giusto per questo, ed ecco perché:

  1. applyè un meccanismo di meta-programmazione, non solo, ma è anche troppo generale per l'attività perché può gestire sequenze di oggetti di diverso tipo, non necessariamente chiamando funzioni di due argomenti. Di conseguenza, alcune volte otterrai un comportamento errato, ad esempio:

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

    Ma intuitivamente, ti aspetteresti una mancata corrispondenza del tipo qui.

  2. Non c'è modo di assicurarsi che applysarà in grado di elaborare tutti gli argomenti che è possibile fornire, in genere è un limite imposto dall'implementazione del linguaggio.

  3. La funzione chiamata applysarà in grado di ottenere un riferimento all'elenco degli argomenti passato in questo modo. Anche questo non è ovvio e può portare a errori in seguito:

    (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 l'elenco degli argomenti viene copiato, si paga il prezzo del consumo di più memoria del necessario, ma se non viene copiato (passato così com'è), si rischia di rovinare l'elenco, se la funzione chiamata lo modifica.


Quindi, il modo migliore per farlo è usare cl-reduce. Il vantaggio è che è stato specificamente progettato per svolgere questo tipo di attività.

(cl-reduce 'concat '("foo" "bar" "baz"))
> "foobarbaz"
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.