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

时间:2015-03-30 03:33:38

标签: lambda lisp elisp common-lisp sharp-quote

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

> (mapcar #'(lambda (x) (+ x 10))
         '(1 2 3))
(11 12 13)

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

在elisp it seems it's not needed at all中。令我惊讶的是,这里没有讨论词法范围,因此不清楚为什么它应该与Common Lisp完全不同。但是this answer说没有引用的lambda表达式没有任何意义,因此,具有讽刺意味的是,有可能引入不带引号的lambda表达式作为引用的语法糖。但这与the elisp manual's claim相矛盾,在Emacs Lisp中,这样的列表是一个有效的表达式,它可以计算出一个函数对象。"

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

4 个答案:

答案 0 :(得分:18)

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

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

  • LAMBDA是一个宏。因此,表单扩展为(function (lambda () ()))
  • (function (lambda () ())) - &gt; FUNCTION是一个特殊的运营商。它返回一个函数对象
  • - &GT;

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

好的,现在出现了一些奇怪的事情:

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

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

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

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

CL-USER 20 > (                  ; <- this is a function call
              (lambda () ())    ; <- this is a lambda expression
              )

再次,上面显示了一个lambda表达式。其中((function (lambda () ())))无效Common Lisp。在函数调用的函数位置,Common Lisp需要函数名或lambda表达式,但不需要评估。

  

和尖引号从名称返回函数对象。

FUNCTION#'是一个简短表示法,从函数名 lambda表达式返回函数对象。

请参阅文档:FUNCTION

  

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

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

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

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

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

(mapcar #'(lambda (x) (* x x)) '(1 2 3))

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

(mapcar (lambda (x) (* x x)) '(1 2 3))

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

(mapcar #'sin '(1 2 3))

答案 1 :(得分:6)

简而言之,您不必尖锐引用lambda,因为它是一个扩展为(function (lambda ...))的宏,并且function可以完成所有魔法。

唯一不需要function的感觉就是你不必自己打字。它是function,而不是lambda,它是基本的运算符。 Lambda表达式本身只是普通列表(function知道如何变成函数对象),而lambda只是一个普通的宏。所以你得到了相反的东西:lambda表达式返回函数对象并不能消除function,因为lambdafunction来解释。 / p>

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

答案 2 :(得分:4)

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

(defmacro lambda (args &body body)
  "Allow (lambda (x) ...) instead of #'(lambda (x) ...)"
  `#'(lambda ,args .,body))

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

On Lisp是一本旧书,它可能是在宏成为标准之前首次发布的。也许保罗格雷厄姆习惯于写#'(lambda ...)并坚持下去。

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

答案 3 :(得分:2)

function关键字似乎在不同的Lisp语言中有不同的含义。

在LISP 1.5中,它用于使用funarg设备创建闭包。 参考:http://c2.com/cgi/wiki?DynamicClosure和LISP 1.5程序员手册,附录B.

在MacLisp中,它被用作编译器的提示,表示lambda表达式可以编译为代码。参考:The Pitmanual, 7. Definitional Forms。它不是用来创建闭包的; *function特殊形式做了类似的事情。参考The Pitmanual, 3. The Evaluator

在Emacs Lisp中,它是对编译器的提示,也可以创建词法闭包。参考:Emacs Lisp Reference Manual, 12.7 Anonymous Functions