假定为 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 () ())) -> 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>
因为上面是一个宏形式,所以先展开再求值。
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,它是网络可读的并且源自标准。
在 Lisp 上阅读绝对有用,但它可能没有完全遵循 ANSI CL 的措辞或语义。 On Lisp 在 CLtL2 之后发布,但在 ANSI CL 之前发布。
在编写代码时实际上意味着什么?
如果你像我一样年纪大了,并且 CLtL1 是你读过 Common Lisp 的最后一件事,那么编写如下代码:
(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))