为什么尖锐引用lambda表达式?

dje*_*lin 14 lisp lambda elisp common-lisp sharp-quote

它是On Lisp中经常使用的一种技术,它位于Common Lisp上:

> (mapcar #'(lambda (x) (+ x 10))
         '(1 2 3))
(11 12 13)
Run Code Online (Sandbox Code Playgroud)

为什么需要锐利报价甚至可能?lambda表达式返回函数对象,而尖锐的引用从名称返回函数对象.我也听说过关于lambda表达式是否是名称的矛盾信息 - 特别是On Lisp与标准相矛盾,但是他的代码似乎也与标准相矛盾.

在elisp中,似乎根本不需要它.令我惊讶的是,这里没有讨论词法范围,因此不清楚为什么它应该与Common Lisp完全不同.但是这个答案说不带引号的lambda表达式没有任何意义,因此,具有讽刺意味的是,有可能引入不带引号的lambda表达式作为引用的语法糖.但这与elisp手册中的声明相矛盾,即"在Emacs Lisp中,这样的列表是一个有效的表达式,可以计算出一个函数对象."

这个问题被标记为普通和e-lisp,因为我试图理解两者的理论模型,并通过了解它们的差异来学习它们.(更实际的是,我正在尝试学习elisp,但在Common Lisp上找到了很多很好的资源,所以我很想学习它们).

Rai*_*wig 19

Common Lisp假定.

为什么需要锐利报价甚至可能?

如果要从函数名称计算函数对象(特别是如果要引用词法绑定)或lambda表达式,则需要特殊运算符FUNCTION或更短的运算符#'.

lambda表达式返回函数对象,

他们没有.甚至无法评估Lambda表达式.

在Common Lisp中,它看起来(lambda () nil)可以被评估.但它不能.

在CLtL1之后的某个时候添加了一个宏LAMBDA,将其扩展为(FUNCTION ...)表达式.这个宏节省了一些打字,让我们的代码看起来更像Scheme.我们来看看这个LAMBDA宏:

CL-USER 17 > (macroexpand-1 '(lambda () ()))  ; not a lambda expression
(FUNCTION 
  (LAMBDA NIL NIL)                            ; <- this is a lambda expression
)
T
Run Code Online (Sandbox Code Playgroud)

这意味着如果您评估,会发生以下情况(lambda () ()):

  • LAMBDA是一个宏.因此表格扩展到(function (lambda () ())).
  • (function (lambda () ()))- > FUNCTION是一个特殊的运营商.它返回一个函数对象
  • - >

如果您写:#'(lambda () ())或者(function (lambda () ())),那么您将跳过宏扩展.

好的,现在有些奇怪了:

CL-USER 18 > (lambda () ())   ; <- this is not a lambda expression.
                              ;    it's a macro form, see above 
#<anonymous interpreted function 40600009FC>
Run Code Online (Sandbox Code Playgroud)

因为上面是一个宏形式,它将首先展开,然后可以进行评估.

CL-USER 19 > (function          ; <- this is a special form
              (lambda () ())    ; <- this is a lambda expression
              )
#<anonymous interpreted function 4060000C0C>
Run Code Online (Sandbox Code Playgroud)

这里真的是一个lambda表达式.在特殊运算符内部,FUNCTION表单不会被宏扩展或类似.

CL-USER 20 > (                  ; <- this is a function call
              (lambda () ())    ; <- this is a lambda expression
              )
Run Code Online (Sandbox Code Playgroud)

再次,上面显示了lambda表达式.哪里((function (lambda () ())))无效Common Lisp.在函数调用的函数位置,Common Lisp需要函数名或lambda表达式,而不是需要计算的东西.

和尖锐的引用从名称返回函数对象.

FUNCTION,为#'简短表示法,从函数名 lambda表达式返回函数对象.

请参阅文档:功能.

我也听说过关于lambda表达式是否是名称的矛盾信息 - 特别是On Lisp与标准相矛盾,但是他的代码似乎也与标准相矛盾.

如果您想听到最后一个字,请阅读ANSI CL标准.或者使用Common Lisp Hyperspec,它是Web可读的并且源自标准.

在Lisp上读取绝对有用,但它可能不完全遵循ANSI CL的措辞或语义.关于Lisp是在CLtL2之后发布的,但是在ANSI CL之前发布.

编写代码时实际意味着什么?

如果你像我一样老了,而且你读过Common Lisp的最后一件事是CLtL1那么就写下代码:

(mapcar #'(lambda (x) (* x x)) '(1 2 3))
Run Code Online (Sandbox Code Playgroud)

如果你年纪大了并且已经和Scheme一起长大,或者更年轻并且已经阅读了Common Lisp Hyperspec,那么你可能想写:

(mapcar (lambda (x) (* x x)) '(1 2 3))
Run Code Online (Sandbox Code Playgroud)

但是对于所有人来说,当涉及到函数名称时,这是默认编写:

(mapcar #'sin '(1 2 3))
Run Code Online (Sandbox Code Playgroud)


gsg*_*gsg 6

简而言之,你不必尖锐引用,lambda因为它是一个扩展到的宏,(function (lambda ...))它就是function所有的魔力.

唯一function没有必要的意义是你不必自己打字.这是function,不lambda,这是基本的操作员.Lambda表达式本身只是普通的列表(它function知道如何变成函数对象),而且lambda只是一个普通的宏.所以你有一些相反的东西:lambda表达式返回函数对象并没有消除,function因为它lambda是用来解释 function.

另一个问题是,在Emacs Lisp中,开头的列表lambda可以直接作为函数处理,而无需经过function.在CL中不是这种情况(尽管可以以形式获得显式转换(coerce some-list 'function)).


Syl*_*ter 6

这一切都与历史有关。(lambda ...)只是#'(lambda ..). Common Lisp 的早期版本没有lambda定义为宏。例如。如果您阅读Peter Norvigs 关于 Quines 的文章(PD,第 2 页),您会看到他明确指出您需要创建这样的宏,如下所示:

(defmacro lambda (args &body body)
  "Allow (lambda (x) ...) instead of #'(lambda (x) ...)"
  `#'(lambda ,args .,body))
Run Code Online (Sandbox Code Playgroud)

因此,在(lambda ...)今天编写时,标准宏会将其重写为#'(lambda ...).

On Lisp是一本旧书,它可能在宏成为标准之前就已经出版了。也可能是保罗格雷厄姆习惯于写作#'(lambda ...)并坚持下去。

我已经看到,当符合更新的标准时,计算机书籍的后续版本通常会尽可能少地更改。我不确定这是一件好事。