首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >为什么funcall忽略词法作用域?

为什么funcall忽略词法作用域?
EN

Stack Overflow用户
提问于 2015-03-30 11:26:58
回答 3查看 122关注 0票数 0

我被this old answer中解释为什么需要尖锐引号的代码激怒了,但我不理解的是为什么funcall似乎跳过了通常的作用域规则。

代码语言:javascript
复制
(defun test () 'red)

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

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

EN

回答 3

Stack Overflow用户

发布于 2015-03-30 15:17:10

假定为通用Lisp。

DEFUN和friends

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

代码语言:javascript
复制
(defun foo () 'foo)

上面我们有一个FOO函数。

让我们称它为:

代码语言:javascript
复制
(funcall (function foo))   ; no lexical bound function available, so it uses
                           ; the symbol's binding

代码语言:javascript
复制
(funcall (symbol-function 'foo))

代码语言:javascript
复制
(funcall 'foo)

代码语言:javascript
复制
(foo)

以上都访问相同的函数。

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

FLET和标签

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

通过(function foo).调用(foo).

  • referencing函数的

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

代码语言:javascript
复制
(flet ((foo () 'bar))   ; <- local lexical scope, function binding

   (foo)                          ; calls the lexical bound function foo

代码语言:javascript
复制
  (funcall (function foo))        ; calls the lexical bound function foo

代码语言:javascript
复制
  (funcall (symbol-function 'foo))   ; calls the symbol's binding,
                                     ; not the lexical binding

代码语言:javascript
复制
  (funcall 'foo)                     ; calls the symbol's binding
                                     ; not the lexical binding

)      
票数 5
EN

Stack Overflow用户

发布于 2015-03-30 14:43:57

这实际上与funcall没有太多关系,而是quotefunction之间的区别。在没有funcall的情况下重试

代码语言:javascript
复制
(defun test () 'red)

(flet ((test () 'green))
  (list 'test #'test)) => (TEST #<FUNCTION (FLET TEST) {C14D26D}>)

其中一个是符号,另一个是函数对象- test的(词法绑定)函数值。如您所见,quote返回它的参数(没有计算它)-这就是忽略词法作用域的地方。

一旦您理解了这种差异,就应该很清楚为什么funcall会像本例中那样工作(至少,如果您理解了funcall是如何对符号进行操作的--请参阅hyperspec entry)。

票数 3
EN

Stack Overflow用户

发布于 2015-03-30 18:40:36

funcall函数接受一个函数指示符(一个函数对象或一个符号)。使用#'foo检索绑定到foo的函数对象,在词法上下文中对其求值。使用'foo,您可以创建符号foo。

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

票数 1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/29337947

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档