編集:最近のEmacsでこれを行うより良い方法は、引数の数をチェックするコンパイラマクロを定義することです。通常のマクロを使用した私の最初の答えは以下に保存されていますが、コンパイラマクロは、実行時funcall
またはapply
実行時に関数を渡すことを妨げないため、優れています。
Emacsの最近のバージョンでは、関数のコンパイラマクロを定義して引数の数をチェックし、一致しない場合は警告(またはエラー)を生成することでこれを行うことができます。唯一の微妙な点は、コンパイラマクロが、評価またはコンパイルのために元の関数呼び出し形式を変更せずに返すことです。これは、&whole
引数を使用し、その値を返すことにより行われます。これは次のように実行できます。
(require 'cl-lib)
(defun my-caller (&rest args)
(while args
(message "%S %S" (pop args) (pop args))))
(define-compiler-macro my-caller (&whole form &rest args)
(when (not (cl-evenp (length args)))
(byte-compile-warn "`my-caller' requires an even number of arguments"))
form)
(my-caller 1 2 3 4)
(my-caller 1 2)
(funcall #'my-caller 1 2 3 4) ; ok
(apply #'my-caller '(1 2)) ; also ok
(my-caller 1) ; produces a warning
(funcall #'my-caller 1 2 3) ; no warning!
(apply #'my-caller '(1 2 3)) ; also no warning
ノートfuncall
やapply
コンパイラマクロによって引数のチェックのバイパス使用できるようになりましたが、彼ら。その名前にもかかわらず、コンパイラマクロも経由して評価を「解釈」の過程で展開されているように見えるC-xC-e、M-xeval-bufferあなたはこの例をコンパイルする上で評価するだけでなく、上のエラーが発生しますので、。
元の答えは次のとおりです。
「展開時に警告を提供するマクロを使用する」というJordonの提案を実装する方法を次に示します。非常に簡単であることがわかりました。
(require 'cl-lib)
(defmacro my-caller (&rest args)
(if (cl-evenp (length args))
`(my-caller--function ,@args)
(error "Function `my-caller' requires an even number of arguments")))
(defun my-caller--function (&rest args)
;; function body goes here
args)
(my-caller 1 2 3 4)
(my-caller 1 2 3)
上記のファイルをコンパイルしようとすると失敗し(.elc
ファイルは生成されません)、コンパイルログにクリック可能なエラーメッセージが表示されます。
test.el:14:1:Error: `my-caller' requires an even number of arguments
エラーの代わりに警告を生成するように置き換え(error …)
て(byte-compile-warn …)
、コンパイルを続行することもできます。(コメントでこれを指摘してくれたJordonに感謝します)。
マクロはコンパイル時に展開されるため、このチェックに関連する実行時のペナルティはありません。もちろん、他の人がmy-caller--function
直接電話をかけるのを止めることはできませんが、ダブルハイフン規則を使用して、少なくとも「プライベート」関数として宣伝することができます。
注目すべき欠点この目的のためにマクロを使用するのは、それはありませんmy-caller
、あなたはそれを渡すことはできません。もはや第一級関数であるfuncall
かapply
、実行時に(あるいは少なくともそれはあなたが何を期待しないだろう)。その点で、このソリューションは、実際の関数に対してコンパイラ警告を単に宣言できるほど優れていません。もちろん、を使用apply
すると、コンパイル時に関数に渡される引数の数をチェックすることが不可能になるため、おそらくこれは許容できるトレードオフです。