来自function
表单的documentation:
与`quote'类似,但对于作为函数的对象更喜欢。 在字节编译中,`function'导致其参数被编译。 “引用”不能那样做。
所以可以#'(lambda ...)
来启用lambda表单的字节编译。
另一方面,as mentioned in the manual,不再需要了。
lambda表单有另一个作用:它通过使用
function
作为子例程告诉Emacs求值程序和字节编译器它的参数是一个函数。
[...]以下表格都是等同的:
(lambda (x) (* x x))
(function (lambda (x) (* x x)))
#'(lambda (x) (* x x))
这使得函数在这种情况下无用。
还有其他情况,功能表格会有用吗?
在任何情况下,它的存在既不必要也不同于quote
?
答案 0 :(得分:12)
#'
(又名function
)由lambda
在内部使用,因为lambda
被定义为将自身包裹在function
中的宏。
但除此之外,你确实可以在不使用#'
的情况下编写任何Elisp代码。还有另外一个细微之处,如果你写#'foo
,你告诉Emacs你认为foo
是一个函数的名称,所以最近版本的字节编译器会警告{{1} }不是一个已知的函数(就像他们多年来一直警告有关foo
的调用一样)。
正如@Bruce指出的那样,使用(foo ...)
代替#'foo
也会对通过'foo
或cl-flet
本地定义的函数产生真正的影响:在这种情况下cl-labels
指的是本地定义的函数,而#'foo
只是引用'foo
符号,它实际上与本地函数定义无关,因此可以通过解绑或绑定到另一个函数:
foo
返回
(cl-flet ((a () 1)) (list 'a (functionp 'a) #'a))
答案 1 :(得分:4)
lambda
是一个宏。它必须扩展,并且每次都要扩展。像这样:
(lambda (x) x) -> (function (lambda (x) x)) ; #'(lambda (x) x)
function
是一个特殊的运营商。事实上,它专门处理lambda
表单,否则我们永远无法扩展lambda
宏:
(lambda (x) x) ->
(function (lambda (x) x)) ->
(function (function (lambda (x) x))) ->
...
function
查看其参数,如果它是lambda
形式,则编译该函数。如果它的参数是一个符号,那么它将搜索与该符号相关联的编译函数。
因此,我们现在看到,function
(如quote
)不评估其论点。它必须具有特殊的行为,因此它是一个特殊的操作符。
答案 2 :(得分:4)
所以人们会
#'(lambda ...)
来启用字节编译 lambda form。另一方面,正如手册中所提到的那样,已经不再存在了 必要的。
程序员不再需要编写(function(lambda ...))(或简写#'(lambda ...) ,因为(lambda ...)扩展为(函数(lambda ...))。其他答案已经很好地解释了。您首先引用函数文档:
从功能表格的文档:
与
quote
类似,但对于作为函数的对象更喜欢。在字节中 编译,function
导致其参数被编译。quote
不能这样做。
因此,功能的文档没有解决
之间的区别(function (lambda …))
和(lambda …)
,而不是
(quote (lambda …))
和(function (lambda …))
。在大多数现代Lisp(Common Lisp,Scheme等)中,表单(quote(lambda ...)),或者只是'(lambda ...))是只是一个列表,它不是可以调用的东西。例如,在SBCL中:
* (funcall '(lambda () 42))
; debugger invoked on a TYPE-ERROR in thread #<THREAD "initial thread" RUNNING {1002978E71}>:
; The value (LAMBDA () 42) is not of type (OR FUNCTION SYMBOL).
但是,在Emacs Lisp中,你可以调用一个列表:
(funcall '(lambda () 42))
;=> 42
在询问功能是否适用于任何目的时,我们必须问“没有它我们能做什么”或“有什么替代方案?”我们无法回答“我们只会写(lambda ...)”,因为正如其他人所指出的那样,只是扩展为(函数(lambda ...))。如果我们没有功能,我们仍然可以使用引用。我们仍然可以写一个扩展为(quote(lambda ...))的 lambda 宏,从而编写(funcall(lambda ...)),并且代码看起来一样。问题是,“有什么区别?”区别在于,在基于 quote 的版本中,我们传递文字列表,并且这些不能编译到函数中,因为我们仍然必须能够使用它们执行类似列表的事情(例如,他们的汽车和 cdr )。 此是功能非常有用的地方,无论我们是自己编写,还是依赖宏来在扩展中使用它。它提供了一种编写功能对象而不是列表的方法。