Emacs Lisp:函数(lambda…)和(lambda…)之间的区别?
两者的区别是什么Emacs Lisp:函数(lambda…)和(lambda…)之间的区别?,emacs,comparison,elisp,Emacs,Comparison,Elisp,两者的区别是什么 (function (lambda ...)) 及 及 ? 在很多情况下,三个似乎是可以互换的。它们是可以互换的。答案是函数允许对lambda进行字节编译,而其他两个则不允许(并且是等效的)。注意:这并不意味着函数实际上是字节编译lambda 你怎么知道呢?一点Emacs lisp内省提供了一些线索。要启动:C-h f功能RET: 函数是'C'中的一种特殊形式 源代码' (函数arg) 喜欢“报价”,但更喜欢 是函数的对象。字节 编译,“函数”导致其 要编译的参数。”引用'
(function (lambda ...))
及
及
?
在很多情况下,三个似乎是可以互换的。它们是可以互换的。答案是
函数
允许对lambda进行字节编译,而其他两个则不允许(并且是等效的)。注意:这并不意味着函数
实际上是字节编译lambda
你怎么知道呢?一点Emacs lisp内省提供了一些线索。要启动:C-h f功能RET:
函数是'C'中的一种特殊形式
源代码'
(函数arg)
喜欢“报价”,但更喜欢
是函数的对象。字节
编译,“函数”导致其
要编译的参数。”引用'
我不能那样做
好的,这就是(函数(lambda…)
和(lambda…)
之间的区别,第一个告诉字节编译器它可以安全地编译表达式。而“ed”表达式不一定要编译(因为它们可能只是一个数字列表)
光是裸的(lambda…
)怎么样?C-h f lambda RET显示:
lambda是'subr.el'中的Lisp宏
(lambda args[docstring][interactive]
(正文)
返回lambda表达式。调用
表单(lambda args docstring
交互主体)是自我引用的;交互主体
评估lambda的结果
表达式就是表达式本身。
lambda表达式可以是
作为函数处理,即存储为
传递的符号的函数值
“funcall”或“mapcar”等
因此,(lambda…
和(lambda…
是等效的
此外,还有表示法#'(lambda…
,它是(function(lambda…)
的语法糖
有关Emacs lisp中函数的更多信息,请阅读
要检查所有这些,可以在*scratch*缓冲区中键入以下内容并计算表达式:
(caddr '(lambda (x) (+ x x)))
(+ x x)
(caddr (lambda (x) (+ x x)))
(+ x x)
(caddr (function (lambda (x) (+ x x))))
(+ x x)
(equal '(lambda (x) (+ x x))
(function (lambda (x) (+ x x))))
t
(equal '(lambda (x) (+ x x))
(lambda (x) (+ x x)))
t
因此,使用lambda的所有三种变体都只是建立了可用作函数的列表(其中一种可能是字节编译的)。那么(引号(lambda…)
和(lambda…)
是不等价的(在字节编译时)。引号中的lambda不是字节编译的,而其他的都是字节编译的
例如:
(defun foo (a)
(byte-code-function-p a))
(defun bar ()
(foo '(lambda () (ignore 'me))))
(defun bar2 ()
(foo (lambda () (ignore 'me))))
(defun bar3 ()
(foo (function (lambda () (ignore 'me)))))
(defun bar4 ()
(foo #'(lambda () (ignore 'me))))
(byte-compile 'bar)
(byte-compile 'bar2)
(byte-compile 'bar3)
(byte-compile 'bar4)
(bar) ; -> nil
(bar2) ; -> t
(bar3) ; -> t
(bar4) ; -> t
您通常不想引用lambda,除非您要将lambda传递给的函数正在对它执行除
funcall
it以外的其他操作。但是在表达式前面不使用单引号,使LISP解释器按原样返回而不计算它吗?这意味着,“(+12)将返回为(+12)并且(+12)将返回为3…@Joscha,不确定您在评论什么部分。Lambda是自引用的,这意味着当解释器计算Lambda表达式时,结果是相同的Lambda表达式。我相信这与大多数其他Lisp不同,因为Emacs使用了变量查找(不确定范围和动态范围)。由于词法范围(我相信),(lambda…
实际上等同于(function(lambda…)
而不是”(lambda…
,您可以通过计算(macroexpand(lambda(x)(+x))来尝试)
@nschum并尝试(macroexpand'(lambda(x)(+x)))
-同样的事情。我相信我已经在我的答案中涵盖了这一点(请参阅倒数第二个相等的语句)。我的错误。宏扩展需要's。(我的示例实际上首先计算lambda…),所以差异实际上是(macroexpand'(lambda…)
与(宏扩展“”(lambda…)
的比较。您的结论不受影响,因为函数
和引号
都实现为返回Fcar(args)
和实际上只是编译器的提示。但是lambda确实返回了函数的提示。我相信随着时间的推移,这种情况已经发生了变化。查看(info“(elisp)匿名函数”)
,它说“现在完全可以省略'function',这是因为'lambda'本身就意味着'function'。”第一次阅读时,该页面有点混乱,但您的示例很好地说明了这一点:)(a)(函数(lambda…)
是(引号(lambda…)
的一个变体,它支持字节编译。(b)未引用的(lambda…
(现在)与(函数(lambda…)
相同!
(caddr '(lambda (x) (+ x x)))
(+ x x)
(caddr (lambda (x) (+ x x)))
(+ x x)
(caddr (function (lambda (x) (+ x x))))
(+ x x)
(equal '(lambda (x) (+ x x))
(function (lambda (x) (+ x x))))
t
(equal '(lambda (x) (+ x x))
(lambda (x) (+ x x)))
t
(defun foo (a)
(byte-code-function-p a))
(defun bar ()
(foo '(lambda () (ignore 'me))))
(defun bar2 ()
(foo (lambda () (ignore 'me))))
(defun bar3 ()
(foo (function (lambda () (ignore 'me)))))
(defun bar4 ()
(foo #'(lambda () (ignore 'me))))
(byte-compile 'bar)
(byte-compile 'bar2)
(byte-compile 'bar3)
(byte-compile 'bar4)
(bar) ; -> nil
(bar2) ; -> t
(bar3) ; -> t
(bar4) ; -> t