Comment appliquer mapcar à une fonction avec plusieurs arguments

8

J'ai des packagesvariables qui ont une liste d'utilisateurs de github et des noms de paquet.

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

Je veux git clonesi le fichier n'existe pas encore.

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

Et je veux appliquer git-cloneà tous les packages variable à packageslister. Mais je ne pouvais pas comprendre comment appliquer avec des arguments.

; This obviously doesn't work
(mapcar `git-clone `packages)
fer à repasser
la source
2
Soit dit en passant, vous avez un supplément 'dans votre defvardéclaration.
Dan
1
FWIW, cela doit être un doublon, mais je n'ai pas le temps de le rechercher. ;-)
Drew

Réponses:

9

Vous pouvez créer une fonction lambda anonyme pour prendre chaque élément de votre liste et lui appliquer votre fonction.

Exemple:

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

Notez que si vous ne vous souciez pas des valeurs de retour (c'est-à-dire que votre fonction est uniquement pour les effets secondaires, ce qui semble être le cas ici), vous pouvez utiliser mapcà la place de mapcar:

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

Pour vos besoins spécifiques, une boucle peut être la plus simple:

(cl-dolist (package packages)      ; or dolist if you don't want to use cl-lib
  (funcall #'toy-fnx (car package) (cdr package)))
Dan
la source
Il n'y a aucun avantage à être cl-dolisttrop clair dolistici.
npostavs
@npostavs: édité.
Dan
Merci! J'ai totalement oublié funcall.
ironsand
3
Hmm, j'ai sauté funcallavant, mais en regardant à nouveau, cela semble redondant, pourquoi ne pas simplement appeler toy-fnxdirectement?
npostavs
@npostavs: correct. C'était juste un moyen d'illustrer la carte et ses amis.
Dan
9

Si vous êtes satisfait de l'utilisation de dash.el, vous pouvez utiliser -eachet déstructurer -let:

(require 'dash)

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

Alternativement, vous pouvez utiliser -lambdadepuis dash.el pour créer une fonction anonyme avec déstructuration:

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

En s'appuyant sur la réponse de Dan , si vous faites ce genre de choses souvent, il peut être utile de définir une variante «étoilée» de mapcar, comme on le fait par exemple en Python:

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

de sorte que par exemple

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