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 cookie và Chính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.