2010-04-17 38 views
22

Tôi đang thực hiện một số cuộc gọi tẻ nhạt đến một loạt các hàm, nhưng các thông số sẽ được xác định khi chạy. Tôi đã viết một chức năng đơn giản để giữ mã DRY của tôi nhưng cho nó một cái tên là không cần thiết. Tôi không sử dụng chức năng này ở bất cứ nơi nào khác.Cách tạo một chức năng tạm thời trong Emacs Lisp

Tôi đang cố gắng để làm điều đó theo cách tôi sẽ trong Đề án, nhưng tôi nhận được một lỗi void-function:

(let ((do-work (lambda (x y z) 
        (do-x x) 
        (do-y y) 
        ;; etc 
       ))) 
    (cond (test-1 (do-work 'a 'b 'c)) 
     (test-2 (do-work 'i 'j 'k)))) 

tôi có thể dính vào tất cả vào một apply (ví dụ, (apply (lambda ...) (cond ...))) nhưng đó không phải là rất dễ đọc. Có cách nào tốt hơn?

Trả lời

27

Giống như các lisps khác (nhưng không phải Đề án), Emacs Lisp có các không gian tên riêng cho các biến và chức năng (nghĩa là ‘Lisp2’, not a ‘Lisp1; xem Technical Issues of Separation in Function Cells and Value Cells cho nguồn gốc và ý nghĩa của các điều khoản này).

Bạn sẽ cần phải sử dụng funcall hoặc apply để gọi một lambda (hoặc chức năng khác) được lưu trữ trong một biến.

(cond (test-1 (funcall do-work 'a 'b 'c)) 
     (test-2 (funcall do-work 'i 'j 'k)) 

Sử dụng funcall nếu bạn luôn gửi cùng một số đối số. Sử dụng apply nếu bạn cần để có thể gửi số lượng đối số thay đổi.

Cơ chế bên trong là mỗi biểu tượng có multiple “cells”. Ô nào được sử dụng tùy thuộc vào where the symbol is in an evaluated form. Khi biểu tượng là phần tử đầu tiên của biểu mẫu được đánh giá, its “function” cell is used. Ở bất kỳ vị trí nào khác, its “value” cell is used. Trong mã của bạn, do-work có chức năng trong ô giá trị của nó. Để truy cập nó dưới dạng hàm bạn sử dụng funcall hoặc apply. Nếu trong ô chức năng, bạn có thể gọi trực tiếp bằng cách sử dụng tên của nó làm ô tô của biểu mẫu được đánh giá. Bạn có thể thực hiện việc này với flet or labels from the cl package.

21

Do (require 'cl) để kéo trong gói Common Lisp, sau đó sử dụng flet thay vì let:

(flet ((do-work (x y z) 
      (do-x x) 
      (do-y y) 
      ;; etc 
     )) 
    (cond (test-1 (do-work 'a 'b 'c)) 
     (test-2 (do-work 'i 'j 'k)))) 
+2

+1. Tôi thực sự không thích Lisp-2. – progo

4

Bạn có thể làm theo cách này ANSI Common Lisp (mặc dù tôi nghĩ rằng có một số devels Emacs mà sẽ cung cấp cho bạn cúng dường):

(flet ((do-work (x y z) 
       (do-x x) 
       (do-y y) 
       ;; etc 
       )) 
    (cond (test-1 (do-work 'a 'b 'c)) 
     (test-2 (do-work 'i 'j 'k)))) 

Dunno nếu trước hết bạn sẽ phải (require 'cl) (hoặc cl-macs) để sử dụng flet. Nếu bạn muốn xác định các hàm đệ quy, bạn sẽ cần sử dụng labels IIRC.

Các vấn đề liên quan