【发布时间】:2016-07-03 16:48:09
【问题描述】:
我正在尝试找出一种安全的方法来检查对象是否为函数(命名或匿名)。
由于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
视情况而定,这意味着添加额外的控制代码、编译代码等。
有效的钩子可以是任何可调用的对象:宏、函数、lambdas 都是有效的钩子。无论如何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 是一个符号,可能需要测试。
据我了解,没有直接的方法来测试可调用对象,因此我尝试了。
【问题讨论】:
-
我不能直接代表 elisp,但这看起来非常糟糕:你可能想要
(or (functionp x) (and (symbolp x) (fboundp x))):你当然不想引用x。即便如此,我还是忘记了(funcall '(lambda ....) ...)是否在 elisp 中工作,或者functionp对此类列表的看法。 -
functionp有什么问题?那就是测试一个对象是否是一个函数的函数。你在说什么错误案例?如果您没有使用与functionp相同的定义,您如何定义“对象是函数”? -
@antonio 那么你想要
functionp。从您的问题看来,您似乎对绑定和宏等问题感到困惑,但 SE 上的 cmets 不是解决这个问题的正确论坛:也许是 irc 或其他东西。 -
“一个 void 对象不是一个函数”:你误解了一些东西。 Emacs Lisp 没有 void 对象。如果
var是一个未绑定的变量,那么(myfunction var)应该 为任何函数myfunction抛出一个错误。它不是一个值为“空对象”的变量,没有这样的东西。它是一个未绑定变量,尝试访问未绑定变量的值是错误的,因为未绑定变量没有值。我坚持,functionp是你要找的,你只是用错了,因为你不懂语言。 -
请不要用
'引用lambda:总是用#'或什么都不引用。
标签: function emacs lambda lisp elisp