Cách áp dụng mapcar cho một hàm có nhiều đối số


8

Tôi có packagescác biến có danh sách người dùng github và tên gói.

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

Tôi muốn git clonenếu tập tin chưa tồn tại.

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

Và tôi muốn áp dụng git-clonecho tất cả các gói biến thành packagesdanh sách. Nhưng tôi không thể tìm ra cách áp dụng với các đối số.

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

2
Nhân tiện, bạn có thêm một phần 'trong defvartuyên bố của bạn .
Dân

1
FWIW, điều này đã phải là một bản sao, nhưng tôi không có thời gian để tìm kiếm nó. ;-)
vẽ

Câu trả lời:


9

Bạn có thể tạo một hàm lambda ẩn danh để lấy từng thành phần trong danh sách của bạn và áp dụng chức năng của bạn cho nó.

Thí dụ:

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

Lưu ý rằng, nếu bạn không quan tâm đến các giá trị trả về (nghĩa là chức năng của bạn chỉ dành cho các tác dụng phụ, dường như là trường hợp ở đây), bạn có thể sử dụng mapcthay cho mapcar:

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

Đối với mục đích cụ thể của bạn, một vòng lặp có thể đơn giản nhất:

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

Không có lợi thế cl-dolisthơn đồng bằng dolistở đây.
npostavs

@npostavs: đã chỉnh sửa.
Dân

Cảm ơn! Tôi hoàn toàn quên mất funcall.
ironsand

3
Hmm, tôi đã bỏ qua funcalltrước đó, nhưng nhìn lại nó có vẻ dư thừa, tại sao không gọi toy-fnxtrực tiếp?
npostavs

@npostavs: đúng. Đó chỉ là một cách để minh họa mapcar và bạn bè.
Dân

9

Nếu bạn hài lòng khi sử dụng dash.el, bạn có thể sử dụng -eachvà hủy bỏ -let:

(require 'dash)

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

Ngoài ra, bạn có thể sử dụng -lambdatừ dash.el để tạo một hàm ẩn danh với hàm hủy:

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

1

Dựa trên câu trả lời của Dan , nếu bạn thực hiện loại điều này thường xuyên, có thể hữu ích để xác định một biến thể 'được gắn dấu sao' mapcar, giống như trong Python:

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

vì vậy, ví dụ

(my-mapcar* #'+ '((1) (1 1) (1 1 1) (1 1 1 1))
      ⇒ (1 2 3 4)  
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.