假设使用的是Common Lisp。
为什么需要或者可能需要井号引用(sharp-quote)?
如果您想从函数名称计算函数对象(特别是如果您想引用词法绑定)或lambda表达式,则需要特殊运算符FUNCTION
,或更短的#'
。
lambda表达式返回函数对象,
不是这样的。Lambda表达式甚至无法被评估。
在Common Lisp中,它看起来像(lambda () nil)
可以被评估。但事实并非如此。
在CLtL1之后的某个时候,添加了一个宏LAMBDA
,将其展开为(FUNCTION ...)
表达式。该宏节省了一些打字,并使代码看起来更像Scheme。让我们检查这个LAMBDA
宏:
CL-USER 17 > (macroexpand-1 '(lambda () ()))
(FUNCTION
(LAMBDA NIL NIL)
)
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
(lambda () ())
)
#<anonymous interpreted function 4060000C0C>
这里是一个lambda表达式。在特殊的运算符FUNCTION
内部,该形式不会被宏展开或类似地处理。
CL-USER 20 > (
(lambda () ())
)
上面展示了一个lambda表达式。其中
((function (lambda () ())))
在Common Lisp中是无效的。在函数调用的函数位置,Common Lisp期望的是函数名或lambda表达式,而不是需要被求值的内容。
而且sharp quoting从名称返回函数对象。
FUNCTION
(其中
#'
是一种简短的符号)从函数名称
或lambda表达式返回函数对象。
请查看文档:
FUNCTION。
我也听到过关于lambda表达式是否是名称的矛盾信息 - 特别是On Lisp与标准相矛盾,但他的代码似乎也可以工作,这也与标准相矛盾。
如果您想听到最后的话,请阅读ANSI CL标准。或者使用Common Lisp Hyperspec,它是可在Web上阅读的,并源自标准。
阅读On 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))
function
引用有助于字节编译器识别应该编译的代码片段。但我同意这可能需要由具有适当洞察力的人更详细地解释。 - tripleee