在 R 中,到底是什么导致对类型名称(或符号)的对象进行求值?
In R, exactly what causes an object of type name (or symbol) to be evaluated?
运行之后:
x <- as.name("aa")
aa <- 2
在 R 中,为什么
(x)
return 2?为什么
x <- as.name("aa")
aa <- 3
get(get(x))
return3?
我知道 get() 需要一个字符串,但我不明白为什么它不计算 x,在其中找到字符串,然后获取它。在我看来,有时函数会对其参数进行此类评估,有时则不会。例如,在第二个示例中,如果将 get(get(x)) 替换为 eval(x),则 eval() 计算 x 以找到名称,然后计算名称以找到 3.
因为x
的值不是2,而是符号(或名称)aa
。但是,如果您 eval
它:
> eval(x)
[1] 2
同样,get(x)
根本不起作用(即产生错误),因为根据 get
的文档,它的第一个参数必须是 an object name (given as a character string)
,其中括号旨在将其与 symbol/name.
区分开来
get
仅适用于字符参数:
> get("aa")
[1] 2
和 symbol
(我发现它比 name
更容易混淆)不是一回事:
> identical("aa",as.name("aa"))
[1] FALSE
(as.name
和 as.symbol
做同样的事情。)
关于 "evaluation of expressions" 与 "evaluation of function arguments" 区别的精彩解释,请参阅@MrFlick 的回答。
我认为@joran 的回答是正确的,但也许我可以尝试用不同的方式解释。
R中的(
"function"本质上就是恒等函数。它回显你传递给它的内容。它几乎就像它不存在一样。这些语句
将 return 编辑的内容没有区别
x #1
(x) #2
((x)) #3
括号只是传递里面的值。您可以根据需要添加任意数量的括号,它不会更改 returned 的内容。评估者查看 ((x))
,查看外括号,并且只知道 return 括号内的值。所以现在它只解析 (x)
,再次,它看到外括号并且只 return 括号内的值,即 x
。括号只是从内部传递值;他们不评价它。
裸值x
是一个名称(或符号)。名称并不唯一地绑定到值。名称和值之间的映射因环境而异。这就是为什么必须在特定上下文中评估名称才能获得值的原因。考虑这些例子
aa <- 5
dd <- data.frame(aa=20)
x <- as.name("aa")
foo <- function(x) {aa<-10; eval(x)}
eval(x)
# [1] 5
foo(x)
# [1] 10
eval(x, dd)
# [1] 20
这种行为实际上是非常可取的。这就是使需要非标准评估工作的功能的原因,例如
subset(mtcars, hp<100)
当您使用 R 控制台时,它的行为与 REPL 相同——它会读取您的输入、对其求值、打印它,然后等待下一个输入。请注意,它只进行一级评估,并且评估发生在 "current" 环境中。它不会递归地评估表达式中的 returned 值。所以当你这样做时
x <- as.name("aa")
x # identical to (x)
# aa
当 REPL 进入评估步骤时,它评估指向名称 aa
的名称 x
。而已。一级评价。名称 aa
随后未被评估。
?eval
帮助页面中有一条说明是这样说的:
eval evaluates its first argument in the current scope before passing it to the evaluator
那里没有 "double" 评估。它只是评估它的参数,就像 R 中的任何其他函数一样。例如
aa <- 5
bar <- function(x) print(x)
bar(aa+2)
# [1] 7
它打印“7”,而不是 "aa+2",因为该函数在打印之前已经评估了它的参数。也解释了这两者的区别
dd <- data.frame(bb=20)
xx <- as.name("bb")
eval(bb, dd)
# Error in eval(bb, dd) : object 'bb' not found
eval(xx, dd)
# [1] 20
在第一个 eval()
调用中,R 无法在当前环境中计算 bb
,因此出现错误。但请注意
evalq(bb, dd)
有效,因为 evalq
不会尝试计算第一个表达式参数。
运行之后:
x <- as.name("aa")
aa <- 2
在 R 中,为什么
(x)
return 2?为什么
x <- as.name("aa")
aa <- 3
get(get(x))
return3?
我知道 get() 需要一个字符串,但我不明白为什么它不计算 x,在其中找到字符串,然后获取它。在我看来,有时函数会对其参数进行此类评估,有时则不会。例如,在第二个示例中,如果将 get(get(x)) 替换为 eval(x),则 eval() 计算 x 以找到名称,然后计算名称以找到 3.
因为x
的值不是2,而是符号(或名称)aa
。但是,如果您 eval
它:
> eval(x)
[1] 2
同样,get(x)
根本不起作用(即产生错误),因为根据 get
的文档,它的第一个参数必须是 an object name (given as a character string)
,其中括号旨在将其与 symbol/name.
get
仅适用于字符参数:
> get("aa")
[1] 2
和 symbol
(我发现它比 name
更容易混淆)不是一回事:
> identical("aa",as.name("aa"))
[1] FALSE
(as.name
和 as.symbol
做同样的事情。)
关于 "evaluation of expressions" 与 "evaluation of function arguments" 区别的精彩解释,请参阅@MrFlick 的回答。
我认为@joran 的回答是正确的,但也许我可以尝试用不同的方式解释。
R中的(
"function"本质上就是恒等函数。它回显你传递给它的内容。它几乎就像它不存在一样。这些语句
x #1
(x) #2
((x)) #3
括号只是传递里面的值。您可以根据需要添加任意数量的括号,它不会更改 returned 的内容。评估者查看 ((x))
,查看外括号,并且只知道 return 括号内的值。所以现在它只解析 (x)
,再次,它看到外括号并且只 return 括号内的值,即 x
。括号只是从内部传递值;他们不评价它。
裸值x
是一个名称(或符号)。名称并不唯一地绑定到值。名称和值之间的映射因环境而异。这就是为什么必须在特定上下文中评估名称才能获得值的原因。考虑这些例子
aa <- 5
dd <- data.frame(aa=20)
x <- as.name("aa")
foo <- function(x) {aa<-10; eval(x)}
eval(x)
# [1] 5
foo(x)
# [1] 10
eval(x, dd)
# [1] 20
这种行为实际上是非常可取的。这就是使需要非标准评估工作的功能的原因,例如
subset(mtcars, hp<100)
当您使用 R 控制台时,它的行为与 REPL 相同——它会读取您的输入、对其求值、打印它,然后等待下一个输入。请注意,它只进行一级评估,并且评估发生在 "current" 环境中。它不会递归地评估表达式中的 returned 值。所以当你这样做时
x <- as.name("aa")
x # identical to (x)
# aa
当 REPL 进入评估步骤时,它评估指向名称 aa
的名称 x
。而已。一级评价。名称 aa
随后未被评估。
?eval
帮助页面中有一条说明是这样说的:
eval evaluates its first argument in the current scope before passing it to the evaluator
那里没有 "double" 评估。它只是评估它的参数,就像 R 中的任何其他函数一样。例如
aa <- 5
bar <- function(x) print(x)
bar(aa+2)
# [1] 7
它打印“7”,而不是 "aa+2",因为该函数在打印之前已经评估了它的参数。也解释了这两者的区别
dd <- data.frame(bb=20)
xx <- as.name("bb")
eval(bb, dd)
# Error in eval(bb, dd) : object 'bb' not found
eval(xx, dd)
# [1] 20
在第一个 eval()
调用中,R 无法在当前环境中计算 bb
,因此出现错误。但请注意
evalq(bb, dd)
有效,因为 evalq
不会尝试计算第一个表达式参数。