为什么funcall会忽略词法范围?

dje*_*lin 0 lisp common-lisp

我被这个旧答案中的代码所激怒,解释了为什么需要尖锐的引用,但我不明白为什么funcall似乎跳过了通常的范围规则.

(defun test () 'red)

(flet ((test () 'green))
  (list (funcall 'test)
        (funcall #'test))) => (red green)
Run Code Online (Sandbox Code Playgroud)

我是否应该将Common Lisp理解为具有由let-family函数设置的"本地"词法范围符号绑定和由de-family函数设置的全局范围变量符号绑定?

Rai*_*wig 5

假设是Common Lisp.

DEFUN和朋友们

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

(defun foo () 'foo)
Run Code Online (Sandbox Code Playgroud)

上面我们有一个功能FOO.

我们称之为:

(funcall (function foo))   ; no lexical bound function available, so it uses
                           ; the symbol's binding
Run Code Online (Sandbox Code Playgroud)

要么

(funcall (symbol-function 'foo))
Run Code Online (Sandbox Code Playgroud)

要么

(funcall 'foo)
Run Code Online (Sandbox Code Playgroud)

要么

(foo)
Run Code Online (Sandbox Code Playgroud)

以上所有都访问相同的功能.

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

FLET和LABELS

FLET和LABELS创建词法范围的函数绑定.FUNCTION可以参考这样的约束力.请注意,在运行时无法通过符号访问这些绑定.只有两种方式:

  • 调用该函数(foo).

  • 通过引用功能(function foo).

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

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

   (foo)                          ; calls the lexical bound function foo
Run Code Online (Sandbox Code Playgroud)

要么

  (funcall (function foo))        ; calls the lexical bound function foo
Run Code Online (Sandbox Code Playgroud)

  (funcall (symbol-function 'foo))   ; calls the symbol's binding,
                                     ; not the lexical binding
Run Code Online (Sandbox Code Playgroud)

  (funcall 'foo)                     ; calls the symbol's binding
                                     ; not the lexical binding

)      
Run Code Online (Sandbox Code Playgroud)