我被this old answer中解释为什么需要尖锐引号的代码激怒了,但我不理解的是为什么funcall似乎跳过了通常的作用域规则。
(defun test () 'red)
(flet ((test () 'green))
(list (funcall 'test)
(funcall #'test))) => (red green)我是否应该将Common Lisp理解为同时具有由let-family函数设置的“局部”词法范围的符号绑定和由de- family函数设置的全局范围的变量符号绑定?
发布于 2015-03-30 15:17:10
假定为通用Lisp。
DEFUN和friends
DEFUN创建了一个全局函数绑定,可以通过符号检索。
(defun foo () 'foo)上面我们有一个FOO函数。
让我们称它为:
(funcall (function foo)) ; no lexical bound function available, so it uses
; the symbol's binding或
(funcall (symbol-function 'foo))或
(funcall 'foo)或
(foo)以上都访问相同的函数。
注意:上面显示了(foo)和(funcall 'foo)调用相同的函数。有一个例外:文件编译器可能会假设函数FOO不会改变。这允许Lisp编译器内联代码或编译成更快的函数调用代码。像在(funcall 'foo)中一样,通过符号调用函数总是会导致对当前和最新绑定的调用-因此总是需要通过符号进行查找。
FLET和标签
FLET和LABELS创建词法范围内的函数绑定。FUNCTION可以引用这样的绑定。请注意,这些绑定不能在运行时通过符号访问。只有两种方法:
通过(function 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
) 发布于 2015-03-30 14:43:57
这实际上与funcall没有太多关系,而是quote和function之间的区别。在没有funcall的情况下重试
(defun test () 'red)
(flet ((test () 'green))
(list 'test #'test)) => (TEST #<FUNCTION (FLET TEST) {C14D26D}>)其中一个是符号,另一个是函数对象- test的(词法绑定)函数值。如您所见,quote返回它的参数(没有计算它)-这就是忽略词法作用域的地方。
一旦您理解了这种差异,就应该很清楚为什么funcall会像本例中那样工作(至少,如果您理解了funcall是如何对符号进行操作的--请参阅hyperspec entry)。
发布于 2015-03-30 18:40:36
funcall函数接受一个函数指示符(一个函数对象或一个符号)。使用#'foo检索绑定到foo的函数对象,在词法上下文中对其求值。使用'foo,您可以创建符号foo。
然后,当funcall将函数指示符映射到函数时,它要么只是标识(如果传递函数对象,则使用它),要么必须在全局环境中查找。
https://stackoverflow.com/questions/29337947
复制相似问题