Ràng buộc nhiều giá trị trực tiếp từ danh sách mà không ràng buộc chính danh sách


12

Có thể gán trực tiếp nhiều giá trị trả về cho các biến mà không cần thông qua một biến tạm thời trong Emacs Lisp không?

Ví dụ: giả sử tôi có một hàm trả về danh sách hai danh sách:

(defun test-func ()
  (setq a '(a b))
  (setq b '(c d))
  `(,a ,b))

Nếu tôi muốn gán giá trị trả về đầu tiên cho list-avà giá trị trả về thứ hai cho list-b, tôi có thể thực hiện việc này bằng cách sử dụng một biến tạm thời temp, ví dụ:

(let* ((temp (test-func)) (list-a (car temp)) (list-b (cadr temp)))
  (message-box (prin1-to-string list-a))
  (message-box (prin1-to-string list-b)))

Có thể làm điều này đơn giản hơn? (Tôi đã quen với Perl và Python khi bạn không phải chỉ định một biến tạm thời)


2
Bạn có thể thử cl-destructuring-bindmacro. Ngoài ra, bạn đã thực sự có ý định sử dụng setqbên trong a defun? setqtạo một biến "đặc biệt" (có thể truy cập toàn cầu), một cái gì đó bạn thường đặt bên ngoài một hàm (bởi vì có rất ít ý nghĩa khi khai báo cùng một biến nhiều lần, trong khi các hàm được dự định chạy nhiều hơn một lần).
wvxvw

@wvxvw Cảm ơn! Có, tôi đã quên sử dụng letbên trong hàm .. Tôi không có kế hoạch đặt bất kỳ biến toàn cục nào :)
Håkon Hægland

Câu trả lời:


8

Lisp chung có một cơ sở đặc biệt - nhiều giá trịthư viện tương thích Emacs Lisp mô phỏng chúng bằng cách sử dụng danh sách .

Do đó bạn có thể làm

(defun test-fun ()
  (let ((a 1) (b 2))
    (cl-values a b)))

(cl-multiple-value-bind (a b) (test-fun)
  ...)

(tải cl-libvà sử dụng cl-tiền tố cho tất cả chức năng CL trong EL).

Lưu ý : nếu bạn nhìn vào câu trả lời SO được liên kết ở trên, bạn sẽ thấy rằng MV mô phỏng với các danh sách là, để đưa nó nhẹ nhàng, dưới mức tối ưu (xem thêm bình luận của @ Stefan bên dưới).


Có bất kỳ lợi thế nào của việc sử dụng multiple-value-bindthay vì cl-multiple-value-bind(chỉ cái sau dường như được ghi lại trong hướng dẫn sử dụng gnu.org/software/emacs/manual/html_node/cl/Mult Môn-Values.html )?
Håkon Hægland

3
@ HåkonHægland Chúng là cùng một chức năng, nhưng bạn nên sử dụng cái sau . Các clgói không có nghĩa là được sử dụng nữa. Bạn nên luôn luôn sử dụng cl-libgói thay thế, trong đó xác định các chức năng với cl-tiền tố ..
Malabarba

1
Tôi khuyên bạn không nên sử dụng cl-values: đó là mô phỏng "nỗ lực tốt nhất" của CommonLisp valuesnhưng nó không thực sự tương thích vì tất cả những gì nó trả về một danh sách (nghĩa là nó là một lời nói dối), và theo kinh nghiệm của tôi, mọi người sớm muộn gì cũng kết thúc thao túng những cái đó như danh sách (tức là phá vỡ sự trừu tượng): sử dụng danh sách một cách rõ ràng (và nếu bạn không thích pcase-let, thì hãy sử dụng cl-destructuring-bindchứ không phải cl-multiple-value-bind).
Stefan

4

Bên cạnh việc dựa vào cl-libgói tương thích, cách được khuyến nghị trong Elisp là sử dụng pcase:

(defun test-fun
  (let ((a '(a b))
        (b '(c d)))
    `(,a ,b)))

(defun other-test-fun ()
  (pcase-let ((`(,a ,b) (test-fun)))
    (message "a = %s; b = %s" a b)))

Bên cạnh pcase-let, cũng có pcase-dolist, pcase-lambdapcasechính nó.

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.