思考这个问题的一种方法是认识到在 CL 中获得一个词法上明显的函数值的唯一方法是特殊运算符function
:如果你想获得与foo
当前词法环境中关联的函数,你必须说(function foo)
:
(flet ((foo (x)
x))
(function foo)
例如。特殊运算符也是如此function
,它可以让您查看函数名称空间中的内容。 function
有一些语法糖,即#'
,以同样的方式quote
(我不打算在下面使用它)。您可以将功能应用程序(f x y)
视为近似(<funcall> (function f) x y)
,其中<funcall>
一些神奇的东西不会反过来被那样替换。
但是你也想要匿名函数,而且,你也可以使用function
它,它的参数是一个lambda 表达式:
lambda 表达式n。在某些上下文中可以用来代替函数名称的列表,通过直接描述函数的行为而不是间接地通过引用已建立函数的名称来表示函数;它的名字来源于它的第一个元素是符号 lambda。– CLHS
所以匿名函数表示为(function (lambda (...) ...))
。如果愿意,您可以将其(lambda (...) ...)
视为函数的“名称”。(我认为人们不喜欢这个,因为它干扰了匿名函数的想法,但很明显,有一组可数的可能的函数“名称”的形式(lambda (...) ...)
,你甚至可以枚举我认为的这个集合(这样做会像枚举有理数一样繁琐)。
由于函数应用程序中的函数位置已经在函数的命名空间中解释,((lambda (...) ...) ...)
表示匿名函数应用程序:它或多或少与(funcall (function (lambda (...) ...) ...)
(再次参见CLHS)相同。
这就是 CL 在 1980 年代某个时候的样子。
然后有一些我不确定的历史混乱:我记得它发生了,但我不记得顺序。首先,在 Lisp-1 中你不需要任何这些function
东西:表单car
表示获取cons的car的函数,你不需要说. 并且类似地表示一个函数。除此之外,还有另一个被提议的 Lisp 标准,它是 ISLisp,可能在这里。虽然 ISLisp 不是 Lisp-1,但它确实有一种表示函数的形式。(function car)
(lambda (...) ...)
(lambda (...) ...)
人们希望 CL 能够与 ISLisp 兼容,这意味着(lambda (...) ...)
应该表示一个函数。其实大家都在偷偷加个定义,比如:
(defmacro lambda (args &body forms)
`(function (lambda ,args ,@forms)))
但是,至关重要的是,您不能在 CL 中便携地执行此操作,因为lambda
它是cl:lambda
并且您不允许重新定义 CL 包中的内容。无论如何人们都这样做了,但结果是他们的程序不便携,并且经常不得不用特殊的魔法装饰来解锁和重新锁定CL
包。
好吧,解决方案是语言必须提供这样的宏。在 CLtL1 定义的语言和最终标准之间的某个时候,这发生了,所以现在lambda
有一个宏定义,其扩展是(或多或少:实现可能允许做特殊的事情)明显的扩展:
(lambda (x) x)
-> #'(lambda (x) x)
所以在现代 CL 中:
- 列表开头
lambda
表示('names')形式(function (lambda (...) ...)
中的函数,例如形式的函数位置((lambda (x) x) 1)
,例如。
lambda
被定义为一个可以扩展的宏,(function (lambda (...) ...))
使其更易于使用。
注意:我认为,您正在使用的实现是允许做它对宏所做的事情,但您不应该依赖这个:
在函数形式出现的词法环境中不表示函数的函数名上使用函数是错误的。具体来说,在表示宏或特殊形式的符号上使用函数是错误的。出于性能原因,实现可能会选择不发出此错误信号,但禁止实现将发出错误信号的失败定义为有用的行为。– CLHS
你真的应该使用macro-function
which 会告诉你是否有宏定义。