2012-01-27 9 views
11

En Common Lisp que pueda hacer esto:asignación de una función sobre dos listas en elisp

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

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

¿Cómo puedo hacer la misma cosa en elisp? Cuando lo intento, me sale un error:

(wrong-number-of-arguments mapcar 3) 

Si mapcar de elisp sólo puede trabajar en una lista a la vez, lo que es la forma idiomáticas para combinar dos listas en una alista?

Respuesta

14

Quiere mapcar*, que acepta una o más secuencias (no solo listas como en Common Lisp), y para un argumento de secuencia funciona igual que el mapcar normal.

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

E incluso si no se define, que fácilmente podría rodar su propia:

(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 ha incorporado en Common Lisp library, que introduce un montón de funciones y macros Common Lisp, pero con la cl- prefijo. No hay razón para evitar esta biblioteca. cl-mapcar es lo que quiere:

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

Con dash biblioteca de listas de manipulación (ver el installation instructions), puede utilizar -zip-with (recuerda: -zip-with es lo mismo que cl-mapcar aplicado a 2 listas):

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

No conozco una manera elegante de implementar un equivalente -zip-with para 3 argumentos. Pero es posible utilizar -partialde dash-functional paquete, que viene con dash (funciones de dash-functional requerir Emacs 24). -partial se aplica parcialmente la función, por lo que estos 2 invocaciones de funciones a continuación son equivalentes:

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

A continuación, se puede usar con una función -reduce:

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

se puede envolver en una función con &rest palabra clave , por lo que esta función aceptaría una cantidad variable de argumentos en lugar de una lista:

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