何时对lambda表达式加引号?


30

问:如果,如果有的话,是很有用锋利引述lambda,当,如果有的话,我们一定锋利引述lambda

人们lambda以三种方式使用:

  1. 平原: (lambda (x) x)
  2. 引: '(lambda (x) x)
  3. 引号: #'(lambda (x) x)

该SO线程讨论了这三种类型,该SO线程说明了为什么不引用(NB:not sharp-quotelambda,并且该SO线程还讨论了引用和尖引号之间的区别。

现在,对匿名函数手动节点和文档字符串lambda注意,lambdas为自报价:

形式的调用(lambda ARGS DOCSTRING INTERACTIVE BODY)是自引用;评估lambda表达式的结果是表达式本身。然后可以将lambda表达式视为一个函数...

因此,似乎(lambda (x) x)#'(lambda (x) x)是等效的,但'(lambda (x) x)不是等效的(最重要的是,在字节编译时)。

似乎很少有人想用a 来引用lambda,但我不清楚何时应该(或不应该)用引号引起来:

  • 引号lambda只是一个风格选择,还是在某些情况下引号实际上有用?
  • 是否在某些情况下我们不能用尖括号将a括起来lambda,即这样做会改变代码的含义?

Answers:


28

曾几何时,对于lambda来说,必须使用引号引起来,现在不再如此。

因此,看来(lambda(x)x)和#'(lambda(x)x)是等效的,但'(lambda(x)x)不相等(最重要的是,在字节编译时)。

是。实际上,前两个在评估时是完全相同的。如您在手册页中所述,您链接:

以下形式都是等效的:

(lambda (x) (* x x)) 
(function (lambda (x) (* x x))) 
#'(lambda (x) (* x x))

除了尝试支持20年前的Emacs版本外,没有理由尖锐地引用lambda了。

所以不要这样


作为旁注:

  • 硬引用lambda(带有')确实会有所作为,它可以防止字节编译。我想不出有用的方案,但谁知道。

  • 反引号是唯一对lambda真正有用的报价,但仅当您出于某种原因不使用词法绑定时才使用。


考虑在手册的“ 匿名函数”部分添加一个链接,其中包含一个示例,解释了引用对字节编译的影响。
君士坦丁

@Constantine完成。我很懒,因为我正在打电话,而OP已经将其链接了。
马拉巴巴

您能否阐明不使用词汇绑定和反引号的意思?谢谢。
coredump 2014年

@coredump使用动态绑定,使外部变量可以在lambda内部访问的唯一方法是手动将lambda构建为内部包含变量的列表。背景知识对这种事情有好处。
马拉巴巴2014年

顺便说一句,我不认为“一次”确实适用:当我在修订历史中调查此主题时,我发现它lambda已被定义为一个宏,该宏将functionfor尽可能地添加回来。如果#'在某个时候需要IOW ,那是在非常早期的开发代码中。它肯定在Emacs-18中已经不需要了。
Stefan

5

由于lambda不加引号没有任何意义,因此最新版本的Emacs Lisp遵循(ANSI)Common Lisp来将未引号解释(lambda...)#'(lambda...)。这两种表示法几乎完全等效(引用结构除外)。

因此,偏好(lambda...)还是#'(lambda...)纯粹是风格问题。有些人喜欢裸露的形式,这样可以避免语法噪音,而其他人(包括我自己)则喜欢引用的形式。


这与elisp手册相矛盾:“在Emacs Lisp中,这样的列表是有效的表达式,其结果为函数对象。”
djechlin

8
“最新版本”,如“ 1990年前后发布的版本” ;-)
Stefan,

0

由于看到#'(lambda ...)是历史遗留物,所以添加了一些其他历史记录

https://debbugs.gnu.org/cgi/bugreport.cgi?bug=4290建议:

从Emacs 22开始,将lambda表单用作函数时,无论其前面是function还是 ,都将对其进行字节编译#'。对于22之前的Emacs版本,必须显式使用,#' 或者function如果要对字节进行形式编译。

我不知道字节编译器,但是我可以看到至少在1993年以前,lambda宏本身就返回了一种(function (lambda ...))形式。

https://www.iro.umontreal.ca/~monnier/hopl-4-emacs-lisp.pdf也表示:

有趣的是(与MacLisp不同),lambda直到1991年左右,在Emacs-19的开发初期,它才作为宏添加到技术上,才成为Elisp语言的一部分。在Emacs-18中,匿名函数被编写为以下形式的带引号的值:

'(lambda (..ARGS..) ..BODY..)

尽管该lambda宏使该引用在近30年之内已不再是必需的,但这种做法的许多实例仍在Elisp代码中出现,即使它阻止了主体的字节编译。与此相关的是,直到1993年,Lucid Emacs 19.8才从MacLisp 导入了#'...阅读器的缩写(function ...)。次年,Emacs也效仿。


0

只是想举一个使用反向Lambda表达式的实际示例。这是关于词法绑定/变量阴影的,使用反向的lambda表达式,并用逗号引用变量,可以获取它们的全局值。

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall `(lambda()
             (let ((my-variable "Random"))
               (message ,my-variable)))))

M-x [RET] eval-buffer 输出“ Random old”

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall (lambda()
             (let ((my-variable "Random"))
               (message my-variable)))))

M-x [RET] eval-buffer 输出“随机”

第三个示例结合了变量的全局变量和局部变量

;; -*- lexical-binding:t -*-
(let ((my-variable "Random old"))
  (funcall `(lambda()
              (let ((my-variable "Random"))
                (message my-variable)
                (message ,my-variable)))))

M-x [RET] eval-buffer 输出“ Random”“ Random old”


@npostavs并不是我的示例的重点,但我也修改了我的示例,以避免同样的错误做法
cjohansson

更好的是,尽管我仍然不相信这是对为内部绑定选择其他名称的一种改进。
npostavs
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.