我试图确定一种安全的方法来检查对象是否是一个函数(命名的或匿名的)。
由于functionp
或fboundp
不能按我预期的那样提供错误,我正在尝试:
(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
不管怎样,看着我的代码,对于这样一个简单的任务来说,它似乎太冗长和复杂了。
有可能使它更好吗?
更新:
如前所述,我澄清了我所说的“
functionp
,fboundp
现在按我的预期工作”。假设我们想检测一个有效的钩子这不起作用:
(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
是一个符号,则可能需要进行测试。据我所知,没有直接的方法来测试对象是可调用的,因此我尝试。
最佳答案
这里的检查有点重复如果使用动态绑定编译代码,(boundp 'x)
将始终是(boundp 'x)
,因为在输入函数时t
是绑定的如果你用代码绑定编译你的代码,x
很可能是(boundp 'x)
,除非你以某种方式创建一个名为nil
的“全局”变量。在这两种情况下,结果都取决于传递给函数的参数。
所以我想你只需要这个:
(defun function-check (x)
(if (symbolp x)
(fboundp x)
(functionp x)))
也就是说,检查
x
是具有函数绑定的符号,还是lambda函数。