尖锐引用 lambda 时的非法函数调用

Illegal function call when sharp-quoting a lambda

如果这两个表达式等价

CL-USER> (lambda (x) (+ x 10))
#<FUNCTION (LAMBDA (X)) {530321CB}>

CL-USER> #'(lambda (x) (+ x 10))
#<FUNCTION (LAMBDA (X)) {5303226B}>

那为什么会出现非法函数调用错误

CL-USER> (#'(lambda (x) (+ x 10)) 10)

而这

CL-USER> ((lambda (x) (+ x 10)) 10)
20 (5 bits, #x14, #o24, #b10100)

效果很好吗?

PS 我正在使用 SBCL。

不同的有效 LAMBDA

(lambda (x) (+ x 10))

LAMBDA 是一个扩展为 (function (lambda ...)).

的宏
#'(lambda (x) (+ x 10))

#' 是一个 reader 宏,它在读取时扩展为 (function ...).

((lambda ...) ...) 是 Common Lisp 中的内置语法。它被定义为一个有效的形式,一个有效的 Lisp 表达式。

使用 LAMBDA 的 Lisp 形式语法无效

((function (lambda ...)) ...) 不是 Lisp 中的有效语法。

复合 Lisp 形式的有效语法

在 Common Lisp 中只有以下复合形式有效:

  • (<special-operator> ...) 用于内置特殊运算符之一
  • (<macro-operator> ...)
  • (<function-operator> ...)
  • (<lambda-expression> ...)

运算符是符号。后者然后将 lambda 表达式作为其第一个元素。示例:

((lambda (x) (1+ x)) 41)

其他语法变体在 Common Lisp 中无效。因此 ((function (lambda ...)) ...)(#'(lambda ...) ...) 不是有效语法。

备注

以上内容有点令人困惑,但这就是它在语言标准中的定义方式。 lambda 宏是在 Common Lisp 的初始设计之后添加的。它允许我们编写类似于 Scheme 的代码:

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

但仍然不是列表的第一个元素被求值的情况,就像在 Scheme 中那样。

原因只是句法规则:被解释为函数调用的形式可以是(参见Common Lisp Glossary):

a) function form,一种形式,它是一个列表,它的第一个元素是要调用的函数的名称,参数是评估的结果函数形式的后续元素。

b) lambda 形式,一种形式,它是一个列表,第一个元素是一个 lambda 表达式,表示要根据参数调用的函数,参数是结果评估 lambda 形式的后续元素。

换句话说,必须解释为函数调用的形式的列表只能将符号、函数名称或以 lambda 开头的列表作为第一个元素,即 lambda表达。不允许使用其他表达式(并且 #'x 只是 (function x) 的缩写,这不是两种情况之一)。

这是由于众所周知的事实,即 Common Lisp 遵循 Lisp-2 模型(参见 What is the difference between Lisp-1 and Lisp-2?)。