elisp:测试一个对象是一个函数

时间:2016-07-03 16:48:10

标签: function emacs lambda lisp elisp

我正在尝试确定一种安全的方法来检查对象是否是一个函数(命名或匿名) 由于functionpfboundp无效,因为我预计会出错,我正在尝试:

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

显然它适用于几种类型的对象:

(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

我们需要使用:

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

虽然这有效,但我们需要确保var无效,否则会出错:

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

根据具体情况,这意味着需要添加额外的控制代码,编译代码等。

有效的钩子可以是任何可调用的对象:宏,函数,lambda是有效的钩子。无论如何functionp不适用于宏:

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

虽然fbound不适用于lambda表达式:

(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 个答案:

答案 0 :(得分:3)

(boundp 'x)检查在这里有点同义反复。如果您使用动态绑定编译代码,(boundp 'x)将始终为t,因为x在进入函数时受到约束。如果您使用词法绑定编译代码,(boundp 'x)可能会nil,除非您以某种方式创建"全局"名为x的变量。在这两种情况下,结果都不会取决于您传递给函数的参数。

所以我认为你只需要这个:

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

即,检查x是具有函数绑定的符号还是lambda函数。