関数をキーにバインドしたり、Mxで呼び出したりできないのはなぜですか?


12

関数を作成し、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
私は、この主題に関するよくある質問に対する一般的な回答としてこの質問を志願します。ただし、同様の問題を抱えている人が質問と回答を見つけやすく、役立つようにするのは理にかなっています。
タイラー

1
これをしてくれてありがとう、タイラー。Qをモデレーターにフラグを立てて、これをコミュニティの質問に変換してください。
ドリュー

私が疑問に思うのは、タイトルがエラーメッセージを引用するだけかどうかです。これは人々が見つけやすくなり、追加するだけで解決できないinteractive場合があります。たとえば、ライブラリの新しいバージョンからコマンドが消えることがあります。このエラーは、Emacsがコマンドを予期する任意のコンテキストで発生する可能性があります。
ドリュー

たとえば、Wikiを検索してcommandp、このの複製として閉じることができる他のQを見つけようとするとよいでしょう。ただし、一部は異なるため、Q&Aを注意深く読んでください。場合によっては、答え(およびQコンテキスト)をここで繰り返す価値があるかもしれません。それ以外の場合、質問は無関係であり、そのままにしておく必要があります(閉じていません)。
ドリュー

1
@Drewタイトルでこれをどのように「宣伝」するのが最善かわからなかった。commandpエラーはキーバインドでのみポップアップするため、Mx方向からこれを実行している人には接続が表示されません。明確で簡潔なタイトルと、関連するすべての検索クエリで表示されるタイトルとの最適なバランスがわからない。自由に調整してください!
タイラー

回答:


21

コアポイントは、関数とコマンドに違いがあるということです。

Emacs lispでは、関数はデフォルトでは対話的に呼び出すことができません。つまりM-x、キーやマウスのクリックを介してアクセスしたり、バインドしたりすることはできません。それをしたい場合は、関数を明示的に宣言する必要がありますinteractive。これ(interactive)は、本文の最初の行として(ドキュメント文字列の後に)フォームを追加することによって行います。インタラクティブ機能はコマンドと呼ばれます。これはマニュアルで説明されています:((info "(elisp) Using Interactive") オンライン版)

表示されるエラーメッセージWrong type argument: commandp, my-functionは、関数をインタラクティブに呼び出そうとしているが、その関数はコマンドではないことを示しています。

実際のエラーを説明するために、この文字pはしばしば述語またはテストを示すためにLispで使用されます。この場合、Emacsはmy-functiontestを使用したコマンドかどうかをテストしてい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 Ceを行う必要があることを明確にしM-x my-functionてください。また、emacsの初心者として、正確に何C-x C-eをするのか、いつ実行する必要があるのか​​はまだ100%明確ではありませんが、実行すると、バッファを解析してmy-functionメモリに上書きするようです実行しないでくださいC-x C-e M-xC-x C-e
-jrh

それは、それが思われるC-x C-e バッファを評価し、それが含むバッファを評価した結果と思われdefunますが、機能を登録しているこの記事では、私はそれだけで機能を実行する必要があることを考えさせるようだ、とまだミニバッファに示されている唯一のものであるがmy-function(関数を返すことを意味しますか?)、ではありませんThis is a great function。ここに何かが欠けているに違いない。
jrh

1
コメントありがとうございます、@ jrh。この質問と回答は、elispの特定の側面、機能をインタラクティブにする方法(つまり、機能をコマンドに変換する方法)に取り組んでいます。あなたはelispのより基本的な側面について尋ねているので、この質問の範囲を超えています。Emacs Lisp Introを使用することをお勧めします。関数を(再)定義するが実際には呼び出さない関数定義の評価と、関数コードを実行する関数の呼び出しの違いについて混乱しているように見えます。
タイラー
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.