为什么函数A主体中的变量查找从全局环境中获取值,而不从调用A的函数B中获取值? [英] Why do variable lookups in the body of function A take values from the global environment but not function B that calls A?

查看:73
本文介绍了为什么函数A主体中的变量查找从全局环境中获取值,而不从调用A的函数B中获取值?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我定义了一个函数:

.get <- function( o, ...) {
    p <- match.call( expand.dots = 0)$...
    cat( sprintf( 'In .get, it is %s.\n', eval( tail( p, 1)[[ 1]])))
    fn <- switch( typeof( o), list =, environment = `[[`, 'S4' = '@', `[`)
    if( length( p)) eval( as.call( c( fn, quote( o), p))) else o # Here when true, I compose a call based on p.
}

然后我尝试如下:

it <- 1
m <- matrix( seq( 9), 3)
sapply( seq( 3), function( it) {
    cat( sprintf( 'In sapply, it is: %s.\n', it))
    .get( m, , it)
})
sapply( seq( 3), function( it) .get( m, , it))

输出:

In sapply, it is: 1.
In .get, it is 1.
In sapply, it is: 2.
In .get, it is 1.
In sapply, it is: 3.
In .get, it is 1.
     [,1] [,2] [,3]
[1,]    1    1    1
[2,]    2    2    2
[3,]    3    3    3

但是预期的输出是:

In sapply, it is: 1.
In .get, it is 1.
In sapply, it is: 2.
In .get, it is 2.
In sapply, it is: 3.
In .get, it is 3.
     [,1] [,2] [,3]
[1,]    1    4    7
[2,]    2    5    8
[3,]    3    6    9

那么it为什么不是1到3(调用函数的值),而是总是在全局环境中分配的值(即1)呢?

So why is it not 1 to 3 (the value it has where the function was called), but always the value assigned in the global environment (i.e. 1)?

推荐答案

您是否在全局环境中与it一起定义了get?如果是这样,那么这可能是一个范围界定问题.请参见此处此处,以进行出色的讨论.

Did you define get in the global environment together with it? If so, then this might be a scoping-issue. See here and here for an excellent discussion.

在第一个链接中查看此示例:

Look at this example from the first link:

 a = 1
 b = 2

 fun <- function(x){ a + b*x }

 new.fun <- function(x){
 a = 2
 b = 1
 fun(x)
 }

 new.fun(2)

如果在new.fun中调用的fun使用全局环境中的ab,则我们期望new.fun(2)的结果为1+2*2=5,而如果它使用函数,则应为2+1*2=4.现在,大多数人期望结果为4,但是结果为5.为什么?因为fun是在全局环境中定义的,所以全局变量ab对于fun很重要.要看到这一点,您可以使用str(fun)查看函数的结构,这将揭示该函数已附加了环境.使用list(environment(fun))查看该环境,您将看到该函数记住"它是在全局环境中定义的.因此,函数fun将首先在此处查找以找到参数ab.

If fun called within new.fun uses a and b from the global environment, we expect the outcome of new.fun(2) to be 1+2*2=5 whereas if it using the parameters defined in the function new.fun, then it should be 2+1*2=4. Now, most people expect the outcome to be 4, but it will be 5. Why? Because fun was defined in the global environment, and hence the global variables a and b matter for fun. To see this, you can look at the structure of the function with str(fun) which will reveal that an environment is attached to the function. Looking into that environment with list(environment(fun)), you will see that the function "remembers" that it was defined in the global environment. For that reason, the function fun will look there first to find the parameters a and b.

为了解决这个问题,已经提出了许多解决方法,如果您使用google词法作用域,则可以找到其中几种方法.有关背景信息,Hadley Wickam的下一本书在环境方面有出色的介绍,请参见此处.有关可能的解决方案,请参见例如此处.解决问题的一种方法是覆盖环境.例如,

To adress the isssue, many workarounds have been proposed, several of which can be found if you google lexical scoping. For background information, Hadley Wickam's upcoming book has an excellent section on environments, see here. For potential solutions, see, for instance here. One way to solve your issue is to overwrite the environment. For instance,

 new.fun2 <- function(x){
 a = 2
 b = 1
 environment(fun) = environment()
 fun(x)
 }

 new.fun2(2)

现在使用父环境(而不是全局环境)中定义的a=2, b=1给出4作为答案.我敢肯定,还有很多更优雅的解决方案.

now gives 4 as the answer, using a=2, b=1 as defined in the parent environment, as opposed to the global environment. I am sure there are many more elegant solutions though.

也就是说,使用

 sapply( seq( 3), function(it) {
   cat( sprintf( 'In sapply, it is: %s.\n', it))
   environment(.get) <- environment()
   .get( m, , it)
 })

有效.

这篇关于为什么函数A主体中的变量查找从全局环境中获取值,而不从调用A的函数B中获取值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆