Como aplicar o mapcar a uma função com vários argumentos

8

Eu tenho packagesvariáveis ​​que têm lista de usuários do github e nomes de pacotes.

(defvar packages '('("auto-complete" . "auto-complete")
                   ("defunkt" . "markdown-mode")))

Quero git clonese o arquivo ainda não existir.

(defun git-clone (author name)
  (let* ((repo-url (concat "[email protected]:" author "/" name ".git")))
    (print repo-url)
    (unless (file-exists-p (concat "~/.emacs.d/git/" name))
      (shell-command (concat "git clone " repo-url " ~/.emacs.d/git/" name)))))

E eu quero aplicar git-clonea todos os pacotes variáveis ​​para packageslistar. Mas não consegui descobrir como aplicar com argumentos.

; This obviously doesn't work
(mapcar `git-clone `packages)
ferros e areias
fonte
2
A propósito, você tem um extra 'na sua defvardeclaração.
Dan
11
FWIW, isso deve ser duplicado, mas não tenho tempo para procurá-lo. ;-)
Drew

Respostas:

9

Você pode criar uma função lambda anônima para pegar cada elemento da sua lista e aplicar sua função a ela.

Exemplo:

(defvar packages '(("auto-complete" . "auto-complete")
                   ("defunkt" . "markdown-mode")))

(defun toy-fnx (author name)
  "Just testing."
  (message "Package %s by author %s" name author)
  (sit-for 1))

(mapcar (lambda (package)
          (funcall #'toy-fnx (car package) (cdr package)))
        packages)

Observe que, se você não se importa com os valores de retorno (ou seja, sua função é apenas para efeitos colaterais, o que parece ser o caso aqui), você pode usar mapcno lugar de mapcar:

(mapc (lambda (package)
        (funcall #'toy-fnx (car package) (cdr package)))
      packages)

Para seus objetivos específicos, um loop pode ser mais simples:

(cl-dolist (package packages)      ; or dolist if you don't want to use cl-lib
  (funcall #'toy-fnx (car package) (cdr package)))
Dan
fonte
Não há nenhuma vantagem para cl-dolistmais dolistaqui.
npostavs
@npostavs: editado.
Dan
Obrigado! Eu esqueci completamente funcall.
ironsand 13/12/2015
3
Hmm, eu pulei o funcallantes, mas olhando novamente parece redundante, por que não ligar toy-fnxdiretamente?
npostavs
@npostavs: correto. Era apenas uma maneira de ilustrar o mapcar e os amigos.
Dan
9

Se você estiver satisfeito com o dash.el, poderá usar -eache destruir -let:

(require 'dash)

(--each packages
  (-let [(author . name) it]
    (git-clone author name)))

Como alternativa, você pode usar -lambdafrom dash.el para criar uma função anônima com a destruição:

(mapcar
 (-lambda ((author . name)) (git-clone author name))
 packages)
Wilfred Hughes
fonte
1

Baseando-se na resposta de Dan , se você costuma fazer esse tipo de coisa, pode ser útil definir uma variante com 'estrela' mapcar, como se faz, por exemplo, em Python:

(defun my-mapcar* (func arglist)
  (mapcar 
     (lambda (args)
       (apply func args))
     arglist))

para que por exemplo

(my-mapcar* #'+ '((1) (1 1) (1 1 1) (1 1 1 1))
      ⇒ (1 2 3 4)  
Abel Stern
fonte