So wenden Sie Mapcar auf eine Funktion mit mehreren Argumenten an


8

Ich habe packagesVariablen, die eine Liste von Github-Benutzern und Paketnamen haben.

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

Ich möchte, git clonewenn die Datei noch nicht existiert.

(defun git-clone (author name)
  (let* ((repo-url (concat "git@github.com:" 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)))))

Und ich möchte auf git-clonealle Pakete Variablen anwenden, um sie aufzulisten packages. Aber ich konnte nicht herausfinden, wie ich mich mit Argumenten bewerben sollte.

; This obviously doesn't work
(mapcar `git-clone `packages)

2
Übrigens haben Sie ein Extra 'in Ihrer defvarErklärung.
Dan

1
FWIW, das muss ein Duplikat sein, aber ich habe keine Zeit, danach zu suchen. ;-)
Drew

Antworten:


9

Sie können eine anonyme Lambda-Funktion erstellen, um jedes Element Ihrer Liste zu übernehmen und Ihre Funktion darauf anzuwenden.

Beispiel:

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

Beachten Sie, dass Sie, wenn Sie sich nicht für die Rückgabewerte interessieren (dh Ihre Funktion ist nur für Nebenwirkungen vorgesehen, was hier der Fall zu sein scheint), mapcanstelle von mapcar:

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

Für Ihre spezifischen Zwecke kann eine Schleife am einfachsten sein:

(cl-dolist (package packages)      ; or dolist if you don't want to use cl-lib
  (funcall #'toy-fnx (car package) (cdr package)))

Es gibt keinen Vorteil, hier cl-dolisteinfach zu sein dolist.
npostavs

@npostavs: bearbeitet.
Dan

Vielen Dank! Ich habe es total vergessen funcall.
Eisen und

3
Hmm, ich habe das funcallvorher übersprungen , aber wenn ich es mir noch einmal ansehe, scheint es überflüssig, warum nicht einfach toy-fnxdirekt anrufen ?
npostavs

@npostavs: richtig. Es war nur eine Möglichkeit, Mapcar und Freunde zu veranschaulichen.
Dan

9

Wenn Sie mit dash.el zufrieden sind, können Sie Folgendes verwenden -eachund destrukturieren -let:

(require 'dash)

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

Alternativ können Sie -lambdavon dash.el aus eine anonyme Funktion mit Destrukturierung erstellen:

(mapcar
 (-lambda ((author . name)) (git-clone author name))
 packages)

1

Aufbauend auf der Antwort von Dan kann es nützlich sein, wenn Sie so etwas häufig tun, eine "markierte" Variante von zu definieren mapcar, wie dies beispielsweise in Python der Fall ist:

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

so dass zB

(my-mapcar* #'+ '((1) (1 1) (1 1 1) (1 1 1 1))
      ⇒ (1 2 3 4)  
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.