2016-07-03 4 views
1

オブジェクトが名前付きか匿名かをチェックする安全な方法を特定しようとしています。どうやらそれは、オブジェクトのいくつかのタイプで動作しますelisp:オブジェクトが関数であることをテストします。

(defun function-check (x) 
    (and (boundp 'x) 
     (if (symbolp x) (fboundp x) 
    (functionp x)))) 

functionpまたはfboundpとして
が、私はエラーを与えて予想したように、私がしようとしています動作しません。とにかく

(setq lfun (lambda() "hello")) 
(function-check lfun) ; -> t 
(setq nfun 'buffer-name) 
(function-check nfun) ; -> t 
(setq slfun '(lambda() "hello")) 
(function-check slfun) ; -> t 

(function-check 'not-bound) ; -> safe nil 

、私のコードを見て、それそのような単純な作業のためにあまりにも冗長で畳み込まれているようです。
それを改善することは可能ですか?

更新:尋ねたよう

、私は私が何を意味するかを明確「functionpfboundpは、今、私が期待どおりに動作します」。

有効なフックを検出するとします。これは動作しません:

(setq var 'buffer-name) 
(functionp 'var)   ;nil 
(fboundp 'var)   ;nil 

我々が使用する必要があります。私たちはvarがそうでなければ、我々は、エラーを取得し、無効でないことを確認する必要があり、

(functionp var)   ;t 
(fboundp var)   ;t 

を、これは動作しますが:

(functionp void-var)  ;Lisp-error 
(fboundp void-var)  ;Lisp-error 

状況に応じて、これは追加の制御コードの追加、コードのコンパイルなどを意味します。

有効なフックは呼び出し可能なオブジェクトです:マクロ、関数、lambdasは有効なフックです。とにかくfunctionpは、マクロでは動作しません:

(defmacro mac() "hello") 
(functionp 'mac) ;nil 

fboundは、ラムダ式では動作しませんが:変数に式を割り当てる場合

(functionp '(lambda() t)) ;t 
(functionp (lambda() t)) ;t 
(fboundp '(lambda() t)) ;Lisp error 
(fboundp (lambda() t)) ;Lisp error 

また、これは起こります:

(setq var '(lambda() t)) 
(functionp var)  ;t 
(fboundp var)  ;Lisp error 

ましたvarがシンボルの場合はテストが必要な場合があります。

私が理解しているように、呼び出し可能なオブジェクトをテストするストレートな方法はないので、私の試みです。

+1

私はelispの手を話すことができませんが、これは恐ろしくバギーに見えます:あなたはおそらく '(または(functionp x)(と(symbolp x)(fboundp x)))' 'を望んでいます: xを引用する。それでも、(funcall(lambda ....)...) 'がelispで動作するのか、' functionp'がそのようなリストについて何を言うのかを忘れてしまいます。 – tfb

+3

'functionp'の何が問題なのですか?これは、オブジェクトが関数かどうかをテストする関数です。あなたは何の誤りを言っていますか?あなたが 'functionp'と同じ定義を使用していないなら、あなたはどのように"オブジェクトは関数 "を定義しますか? – Gilles

+0

@Gilles私は 'functionp'はあなたが言うようにおそらく答えだと思います:それはelispで'(functionp 'car) 'が真であるように見えます:Common Lispではfalseです。 – tfb

答えて

3

(boundp 'x)小切手はこちらです。動的バインディングを使用してコードをコンパイルする場合は、(boundp 'x)は、関数を入力するときにはxがバインドされているので、常にtになります。字句結合でコードをコンパイルする場合は、xという名前の「グローバル」変数を何らかの形で作成しない限り、(boundp 'x)はおそらくnilになります。どちらの場合も、結果は関数に渡す引数に依存します。

だから私はあなただけでこれを必要だと思う:

(defun function-check (x) 
    (if (symbolp x) 
     (fboundp x) 
    (functionp x))) 

つまり、xが結合機能、またはラムダ関数を持っているシンボルのいずれかであることを確認してください。

+3

これは 'functionp'と比べてどのように劣っていないのですか?あなたの関数は、関数として実行可能でない関数バインディングを持つシンボルに対して 't'を返します。シンボルを渡すと、 'fboundp'はその関数バインディングが関数であることを正しくチェックします。 – Gilles

0

AUCTeXパッケージで使用される関数述語の興味深い例が見つかりました。

(defun TeX-function-p (arg) 
    "Return non-nil if ARG is callable as a function." 
    (or (and (fboundp 'byte-code-function-p) 
     (byte-code-function-p arg)) 
     (and (listp arg) 
     (eq (car arg) 'lambda)) 
     (and (symbolp arg) 
     (fboundp arg)))) 

このテストでは、連想リストTeX-expand-listを解析して得られたTeXコマンド(のコンポーネント)を呼び出す前AUCTeXに使用されます。
連想リストで見つかった拡張が関数である場合、それを使って呼び出される:TeX-expand-listは巨大で、カスタマイズ可能であるよう

(apply expansion arguments) 

TeX-function-pは、徹底しており、拡張も記号ではないオブジェクトになる可能性がありますまたは拘束されていないシンボル。

この関数は、functionpが呼び出し可能オブジェクトをテストするには必ずしも十分ではないことを示しているという点で私の質問に答えています。

+0

'functionp'はそれのどの部分をまだ処理していませんか? 'TeX-function-p 'が書かれた時点で必要だったかもしれませんが、今は私には冗長に見えます。 – phils

+0

@phils:もう少し調査した後、私は[バグレポート](http://lists.gnu.org/archive/html/bug-gnu-emacs/2016-08/msg00537.html)をサブメートしました。ニュースが到着すると、私はそれに応じてこの投稿を編集します。 – antonio

関連する問題