2012-01-27 15 views
11

In Common Lisp posso fare questo:Mappatura una funzione più di due liste in elisp

(mapcar #'cons '(1 2 3) '(a b c)) 

=> ((1 . A) (2 . B) (3 . C)) 

Come posso fare la stessa cosa in elisp? Quando provo, ottengo un errore:

(wrong-number-of-arguments mapcar 3) 

Se mapcar di elisp può funzionare solo in una sola lista alla volta, qual è il modo idomatic per combinare due liste in un alist?

risposta

14

Si desidera mapcar*, che accetta una o più sequenze (non solo liste come in Common Lisp), e per un argomento di sequenza funziona come il normale mapcar.

(mapcar* #'cons '(1 2 3) '(a b c)) 
((1 . A) (2 . B) (3 . C)) 

E anche se non sono stati definiti, si potrebbe facilmente rotolare il proprio:

(defun mapcar* (f &rest xs) 
    "MAPCAR for multiple sequences" 
    (if (not (memq nil xs)) 
    (cons (apply f (mapcar 'car xs)) 
     (apply 'mapcar* f (mapcar 'cdr xs))))) 
8

Emacs è dotato di Common Lisp library, che introduce un sacco di funzioni Common Lisp e macro, ma con la cl- prefisso. Non c'è motivo di evitare questa libreria. cl-mapcar è ciò che si vuole:

(cl-mapcar '+ '(1 2 3) '(10 20 30)) ; (11 22 33) 

Con dash biblioteca lista di manipolazione (vedi installation instructions), è possibile utilizzare -zip-with (ricordate: -zip-with è lo stesso cl-mapcar applicato a 2 liste):

(-zip-with '+ '(1 2 3) '(10 20 30)) ; (11 22 33) 

Non conosco un modo elegante per implementare un equivalente -zip-with per 3 argomenti. Ma è possibile utilizzare -partial da dash-functional pacchetto, che viene fornito con dash (funzioni da dash-functional richiedere Emacs 24). -partial vale in parte la funzione, in modo da questi 2 invocazioni funzione qui sotto sono equivalenti:

(-zip-with '+ '(1 2) '(10 20)) ; (11 22) 
(funcall (-partial '-zip-with '+) '(1 2) '(10 20)) ; (11 22) 

Quindi, è possibile utilizzarlo con una funzione -reduce:

(-reduce (-partial '-zip-with '+) '((1 2 3) (10 20 30) (100 200 300))) 
; (111 222 333) 

si può avvolgere in una funzione con &rest parola chiave , quindi questa funzione accetta una quantità variabile di argomenti anziché una lista:

(defun -map* (&rest lists) 
    (-reduce (-partial 'zip-with '+) lists))