Lisp 为什么funcall忽略了词法范围?

Lisp 为什么funcall忽略了词法范围?,lisp,common-lisp,Lisp,Common Lisp,在解释为什么需要尖引号时,我被代码激怒了,但我不明白的是为什么funcall似乎跳过了通常的范围规则 (defun test () 'red) (flet ((test () 'green)) (list (funcall 'test) (funcall #'test))) => (red green) 我是否应该将Common Lisp理解为既有let族函数设置的“局部”词汇范围符号绑定,又有de-family函数设置的全局范围变量符号绑定?这实际上与funcal

在解释为什么需要尖引号时,我被代码激怒了,但我不明白的是为什么
funcall
似乎跳过了通常的范围规则

(defun test () 'red)

(flet ((test () 'green))
  (list (funcall 'test)
        (funcall #'test))) => (red green)

我是否应该将Common Lisp理解为既有let族函数设置的“局部”词汇范围符号绑定,又有de-family函数设置的全局范围变量符号绑定?

这实际上与
funcall
没有太大关系,而是
引号
函数
之间的区别。请在不使用
funcall
的情况下重试:

(defun test () 'red)

(flet ((test () 'green))
  (list 'test #'test)) => (TEST #<FUNCTION (FLET TEST) {C14D26D}>)
(defun测试()红色)
(flet((测试()'绿色))
(列出“测试”)测试)=>(测试)
其中一个是符号,另一个是函数对象,即
测试的(词汇绑定)函数值。如您所见,
quote
返回它的参数(不计算它)——这就是忽略词法范围的地方


一旦您了解了这一差异,就应该非常清楚为什么
funcall
的行为与本例中的行为相同(至少,如果您了解funcall是如何对符号进行操作的,请参阅参考资料)。

假定使用公共Lisp

DEFUN和朋友们

DEFUN创建一个全局函数绑定,该绑定可以通过符号检索

(defun foo () 'foo)
上面我们有一个函数FOO

我们称之为:

(funcall (function foo))   ; no lexical bound function available, so it uses
                           ; the symbol's binding

所有这些都访问相同的功能

注意:上面显示了
(foo)
(funcall'foo)
调用相同的函数。有一个例外:文件编译器可能会假定函数
FOO
不会更改。这允许Lisp编译器内联代码或编译为更快的函数调用代码。通过
(funcall'foo)
中的符号调用函数总是导致调用当前和最新绑定-因此始终需要通过符号进行查找

FLET和标签

FLET和标签创建词汇范围的函数绑定<代码>函数
可以引用这样的绑定。请注意,在运行时不能通过符号访问这些绑定。只有两种方法:

  • 调用函数
    (foo)

  • 通过
    (函数foo)
    引用函数

由于两者都使用静态词法引用,因此在运行时不会通过符号或类似方式进行查找。这意味着,符号在运行时不涉及词法函数——它们只在源代码中可见

(flet ((foo () 'bar))   ; <- local lexical scope, function binding

   (foo)                          ; calls the lexical bound function foo
但是


funcall
函数采用函数指示符(函数对象或符号)。使用
#'foo
检索绑定到
foo
的函数对象,在词汇上下文中对其进行计算。使用
'foo
,可以创建符号foo


funcall
将函数指示符映射到函数时,它要么只是标识(如果传递函数对象,则使用该标识),要么必须在全局环境中查找

这不是关于
funcall
,而是关于
#
函数
特殊运算符。对我来说,这似乎更像是关于
引用
(funcall 'foo)
(foo)
(flet ((foo () 'bar))   ; <- local lexical scope, function binding

   (foo)                          ; calls the lexical bound function foo
  (funcall (function foo))        ; calls the lexical bound function foo
  (funcall (symbol-function 'foo))   ; calls the symbol's binding,
                                     ; not the lexical binding
  (funcall 'foo)                     ; calls the symbol's binding
                                     ; not the lexical binding

)