我正在尝试确定一种安全的方法来检查对象是否是一个函数(命名或匿名)
由于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
是符号,可能需要进行测试。
据我了解,没有直接的方法来测试对象是否可调用,因此我的尝试。
答案 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函数。