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