Tại sao tôi không thể liên kết chức năng của mình với khóa hoặc gọi nó bằng Mx?


12

Tôi đã viết một hàm và tôi muốn gọi nó qua Mx và liên kết nó với một khóa. Đây là chức năng của tôi:

(defun my-function ()
    (message "This is a great function"))

Nếu tôi cố gắng gọi nó bằng M-x my-function, tôi sẽ gặp lỗi: [no match]trong bộ đệm mini.

Nếu tôi cố gắng liên kết nó với một phím (hoặc nhấp chuột):

(global-set-key (kbd "C-c a") 'my-function)

Nó có vẻ hoạt động, nhưng khi tôi cố gắng gọi nó C-c a, tôi gặp lỗi

Đối số kiểu sai: Commandp, my-function

Tại sao tôi không thể sử dụng chức năng của mình?


5
Tôi tình nguyện trả lời câu hỏi này như một câu trả lời chung cho các câu hỏi thường gặp về chủ đề này. Tuy nhiên, hãy thoải mái mở rộng hoặc làm rõ ý nghĩa để làm cho câu hỏi và câu trả lời có thể khám phá được bằng cách & hữu ích cho những người có vấn đề tương tự!
Tyler

1
Cảm ơn vì đã làm điều này, Tyler. Tôi đã gắn cờ Q cho người điều hành để vui lòng chuyển đổi câu hỏi này thành câu hỏi của cộng đồng.
vẽ

Một điều tôi tự hỏi là liệu tiêu đề có nên trích dẫn thông báo lỗi hay không. Điều đó có thể dễ dàng hơn cho mọi người tìm thấy và nó có thể cho phép các câu trả lời không phải làm chỉ bằng cách thêm interactive- ví dụ, đôi khi một lệnh biến mất khỏi phiên bản mới của thư viện. Lỗi có thể được đưa ra trong bất kỳ bối cảnh nào mà Emacs mong đợi một lệnh.
vẽ

Sẽ tốt hơn nếu bây giờ mọi người đã tìm kiếm wiki commandpđể cố gắng tìm các Q khác có thể được đóng lại dưới dạng các bản sao của cái này. Tuy nhiên, hãy cẩn thận để đọc Q & A, vì một số khác nhau. Trong một số trường hợp, câu trả lời (và bối cảnh Q) có thể đáng để nhắc lại ở đây. Trong các trường hợp khác , câu hỏi không liên quan và nên để nguyên trạng (không đóng).
vẽ

1
@Drew Tôi không chắc chắn cách tốt nhất để 'quảng cáo' này trong tiêu đề. Lỗi lệnh chỉ bật lên với các phím bấm, vì vậy mọi người chạy vào đây từ hướng Mx sẽ không thấy kết nối. Không chắc chắn sự cân bằng tốt nhất là gì giữa một tiêu đề rõ ràng, súc tích và một tiêu đề sẽ bật lên cho tất cả các truy vấn tìm kiếm có liên quan. Hãy thoải mái để điều chỉnh như bạn muốn!
Tyler

Câu trả lời:


21

Điểm cốt lõi là có sự khác biệt giữa hàm và lệnh .

Trong lac Emacs, các chức năng không thể gọi tương tác theo mặc định. Điều đó có nghĩa là bạn không thể truy cập chúng thông qua M-xhoặc liên kết chúng với một phím hoặc nhấp chuột. Nếu bạn muốn làm điều đó, bạn cần khai báo rõ ràng hàm sẽ được interactivethực hiện bằng cách thêm một (interactive)biểu mẫu làm dòng đầu tiên trong phần thân (theo chuỗi tài liệu). Một chức năng tương tác được gọi là lệnh Điều này được giải thích trong hướng dẫn: (info "(elisp) Using Interactive") (phiên bản trực tuyến) .

Thông báo lỗi bạn thấy, Wrong type argument: commandp, my-functioncho biết bạn đang cố gắng gọi một chức năng một cách tương tác, nhưng chức năng đó không phải là một lệnh .

Để giải thích lỗi thực tế, chữ cái pthường được sử dụng trong lisp để chỉ vị ngữ hoặc kiểm tra. Trong trường hợp này, Emacs đang thử nghiệm my-functionđể xem đó có phải là lệnh sử dụng thử nghiệm hay không commandp. Nó không, dẫn đến lỗi. Các lỗi tương tự bật lên bất cứ khi nào bạn sử dụng một đối tượng sai loại: nếu Emacs mong đợi một chuỗi và bạn truyền một ký hiệu, chẳng hạn, bạn có thể thấy một tham chiếu đến stringp.

Để trả lời câu hỏi như đã hỏi, bạn cần thêm (interactive)dòng vào định nghĩa:

(defun my-function ()
    (interactive)
    (message "This is a great function"))

rất nhiều tùy chọn cho interactivebiểu mẫu, hỗ trợ tất cả các cách truyền thông tin đến chức năng của bạn. Kiểm tra hướng dẫn cho tất cả các chi tiết.

Macro bàn phím là một trường hợp đặc biệt trong bối cảnh này. Một macro bàn phím là một chuỗi các sự kiện đầu vào, được biểu diễn dưới dạng một chuỗi. Các macro bàn phím hoạt động giống như các lệnh, vì vậy bạn có thể liên kết chúng với các phím mà không cần lo lắng về việc thêm một interactivekhai báo. Ví dụ: trong các mục sau:

(global-set-key (kbd "C-c l") "λ")

"λ"là một macro bàn phím, vì vậy chúng ta có thể liên kết nó C-c lmà không gặp vấn đề gì. Nếu chúng ta cố gắng làm điều tương tự với một hàm, chúng ta phải chắc chắn xác định hàm là interactive:

(global-set-key (kbd "C-c k") 
  (lambda () (insert "λ"))
;; C-c k is undefined! We tried to bind it to a function

(global-set-key (kbd "C-c m") 
  (lambda () (interactive) (insert "λ"))
;; C-c m is bound to a command that inserts λ

một gợi ý tôi muốn thêm vào, làm rõ rằng bạn cần phải làm Cx Ce trước khi thực hiện M-x my-functiontrong ví dụ của mình. Ngoài ra, với tư cách là người mới bắt đầu, tôi thực sự chưa rõ ràng 100% về chính xác những gì C-x C-ehoặc khi bạn cần chạy nó, nhưng có vẻ như ... khi bạn chạy nó, nó phân tích bộ đệm và ghi đè lên my-functionbộ nhớ bởi vì nếu tôi không chạy C-x C-e M-xchạy hàm từ lần cuối cùng tôi chạyC-x C-e
jrh

Có vẻ như C-x C-e đánh giá bộ đệm , có vẻ như là kết quả của việc đánh giá bộ đệm chứa a defunđang đăng ký chức năng, mặc dù bài viết này dường như khiến tôi nghĩ rằng nó chỉ nên chạy chức năng, và điều duy nhất hiển thị trong bộ xử lý nhỏ là my-function(ngụ ý nó trả về hàm?), không This is a great function. Tôi phải thiếu một cái gì đó ở đây.
giờ 44 phút

1
Cảm ơn ý kiến ​​của bạn, @jrh. Câu hỏi & câu trả lời này đang giải quyết một khía cạnh cụ thể của elisp, làm thế nào để làm cho một chức năng tương tác (nghĩa là biến chức năng thành một lệnh). Bạn đang hỏi về các khía cạnh cơ bản hơn của elisp, và nằm ngoài phạm vi của câu hỏi này. Tôi khuyên bạn nên làm việc thông qua phần giới thiệu Emacs Lisp. Bạn dường như bối rối về sự khác biệt giữa việc đánh giá một định nghĩa hàm, trong đó (lại) định nghĩa một hàm nhưng thực tế không gọi nó và gọi hàm, chạy mã chức năng.
Tyler
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.