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

最佳答案

这里的检查有点重复如果使用动态绑定编译代码,(boundp 'x)将始终是(boundp 'x),因为在输入函数时t是绑定的如果你用代码绑定编译你的代码,x很可能是(boundp 'x),除非你以某种方式创建一个名为nil的“全局”变量。在这两种情况下,结果都取决于传递给函数的参数。
所以我想你只需要这个:

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

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

10-07 13:37
查看更多