为什么不能将函数绑定到键或用Mx调用它?


13

我编写了一个函数,我想通过Mx调用它,并将其绑定到键上。这是我的功能:

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

如果尝试使用调用它M-x my-function,则会[no match]在迷你缓冲区中收到错误消息:。

如果我尝试将其绑定到键(或单击鼠标):

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

它似乎可以工作,但是当我尝试用调用时C-c a,出现错误

类型参数错误:commandp,my-function

为什么我不能使用我的功能?


5
我自愿提出这个问题,作为对这个问题的常见问题的一般回答。可以随意扩展或阐明,使有问题的人可以发现并回答问题和答案是有意义的!
泰勒(Tyler)

1
谢谢你这样做,泰勒。我已标记Q为主持人,请将其转换为社区问题。
提请

我想知道的一件事是标题是否应该仅引用错误消息。这对于人们来说可能更容易找到,并且可能允许与添加无关的答案interactive-例如,有时命令从新版本的库中消失。在Emacs需要命令的任何上下文中都可以引发该错误。
提请

如果人们现在在Wiki上搜索commandp来寻找其他可以作为该Q的副本关闭的Q,那将是一个很好的选择。但是,请仔细阅读问答,因为其中一些有所不同。在某些情况下,答案(和Q语境)在这里可能值得重复。在其他情况下,该问题是无关的,应保留原样(不关闭)。
提请

1
@Drew我不确定如何最好地在标题中“做广告”。commandp错误仅会通过按键绑定弹出,因此从Mx方向碰到这个错误的人将看不到连接。不确定清晰,简洁的标题和将为所有相关搜索查询弹出的标题之间的最佳平衡是什么。随意调整!
泰勒(Tyler)

Answers:


22

核心是功能和命令之间存在差异

在Emacs lisp中,默认情况下不能交互调用函数。这意味着您无法通过访问它们M-x或将它们绑定到按键或鼠标单击。如果要这样做,则需要将函数显式声明为,方法是在主体的第一行中interactive添加一个(interactive)表单(紧随文档字符串之后)。交互式功能称为命令。在手册中对此进行了说明:((info "(elisp) Using Interactive") 在线版本)

您看到的错误消息Wrong type argument: commandp, my-function表示您正在尝试以交互方式调用一个函数,但该函数不是command

为了解释实际错误,该字母p经常用大写字母表示指示谓词或测试。在这种情况下,Emacs正在测试my-function以查看它是否是使用test的命令commandp。不是,这会导致错误。每当使用错误类型的对象时,都会弹出类似的错误:例如,如果Emacs需要一个字符串并传递一个符号,则可能会看到对的引用stringp

要按要求回答问题,您需要(interactive)在定义中添加以下行:

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

表单有很多选项interactive,支持将信息传递到函数的各种方式。查看手册以获取所有详细信息。

在这种情况下,键盘宏是一种特殊情况。键盘宏是一系列输入事件,用字符串表示。键盘宏的行为类似于命令,因此您可以将它们绑定到键,而不必担心添加interactive声明。例如,在以下内容中:

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

"λ"是键盘宏,因此我们可以C-c 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 λ

我想补充的一项建议是,明确说明在进行示例之前,您需要先进行Cx CeM-x my-function。另外,作为emacs初学者,我真的还不清楚100%到底C-x C-e是什么功能或什么时候需要运行它,但是看来……当您运行它时,它会解析缓冲区并覆盖my-function内存,因为如果我不要运行C-x C-e M-x我上次运行时运行的函数C-x C-e
jrh

似乎C-x C-e 对缓冲区进行了评估,似乎对包含a的缓冲区进行评估的结果defun是正在注册该函数,尽管本文似乎使我认为它应该只运行该函数,但是minibuffer中唯一显示的是my-function(暗示它返回函数?),而不是This is a great function。我一定在这里想念什么。
jrh

1
感谢您的评论,@ jrh。该问题和答案针对elisp的特定方面,即如何使功能具有交互性(即,将功能转换为命令)。您正在询问elisp的更多基本方面,并且超出了此问题的范围。我建议您阅读Emacs Lisp简介。您似乎对评估一个函数定义(重新定义一个函数但实际上并未调用它)与调用运行函数代码的函数之间的区别感到困惑。
泰勒(Tyler)
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.