来自C / Python / Java背景,我无法理解一些R语法,其中文字看起来像变量,但似乎表现得像字符串。例如:
library(ggplot2)
library("ggplot2")
两条线的行为相当。但是,我希望第一行的意思是“加载名称存储在ggplot2变量中的库”并给出类似object 'ggplot2' not found
的错误。
说到ggplot2:
ggplot(data, aes(factor(arrivalRate), responseTime, fill=factor(mode))) +
geom_violin(trim=FALSE, position=dodge)
变量arrivalRate
,responseTime
和mode
不存在,但不知何故R知道在data
数据框内查找它们。我假设aes
实际上接收字符串,然后使用类似eval
的内容进行处理。
R如何解析最终将某些文字解释为字符串的代码?
答案 0 :(得分:28)
当一个参数传递给一个函数时,它不会作为值传递,而是作为 promise 传递,其中包含
pryr包可以在承诺中显示信息:
library(pryr)
g <- function(x) promise_info(x)
g(ggplot2)
,并提供:
$code
ggplot2 <-- the promise x represents the expression ggplot2
$env
<environment: R_GlobalEnv> <-- if evaluated it will be done in this environment
$evaled
[1] FALSE <-- it has not been evaluated
$value
NULL <-- not filled in because promise has not been evaluated
pryr输出中的上述插槽中唯一一个可以在R级别访问而无需编写C函数(或使用诸如访问此类C代码的pryr之类的包)的代码插槽。这可以使用R函数substitute(x)
(或其他方法)来完成。就应用于promise的pryr输出substitute
而言,返回代码槽而不评估promise。也就是说,不修改值槽。如果我们以普通的方式访问x
,即不通过substitute
,那么代码将在promise的环境中进行评估,存储在值槽中,然后传递给访问函数中的表达式它。
因此,下列任何一个都会产生一个字符串,表示作为表达式传递的内容,即代码槽的字符表示形式,而不是其值。
f <- function(x) as.character(substitute(x))
f("ggplot2")
## [1] "ggplot2"
f(ggplot2)
## [1] "ggplot2"
事实上,library
使用这个成语,即as.character(substitute(x))
来处理它的第一个参数。
aes
函数使用match.call
将整个调用作为表达式进行处理,因此在某种意义上是substitute
的替代方法。例如:
h <- function(x) match.call()
h(pi + 3)
## h(x = pi + 3)
如果不查看函数的文档或代码如何处理其参数,就无法分辨。
答案 1 :(得分:20)
R语言的一个有趣的怪癖是它评估表达式的方式。在大多数情况下,R的行为与您期望的一样。引号中的表达式被视为字符串,其他任何内容都被视为变量,函数或其他标记。但是一些函数允许“非标准评估”,其中或多或少地评估不带引号的表达式,就好像它是引用变量一样。最常见的例子是R的加载库的方式(允许不带引号或引用的库名称)及其简洁的公式接口。其他包可以利用NSE。 Hadley Wickham在他非常受欢迎的 tidyverse 包中广泛使用它。除了为用户保存几个字符的输入外,NSE还有许多用于动态编程的有用属性。
如另一个答案所述,Wickham有an excellent tutorial on how it all works。 RPubs用户lionel也有一个great working paper on the topic。
答案 2 :(得分:7)
这个概念被称为&#34;非标准评估&#34;,并且有许多不同的方式可以在不同的R函数中使用它。有关简介,请参阅this book chapter。
这种语言功能可能令人困惑,library()
函数可能不需要它,但是当你需要在数据帧上指定计算时,它允许非常强大的代码,如ggplot2或dplyr中的情况,例如。
答案 3 :(得分:5)
行
library(ggplot2)
library("ggplot2")
不等同。在第一行中,ggplot2
是一个符号,可以
或者可能不受某种价值的约束。在第二行中,"ggplot2"
是一个
长度为一的字符向量。
然而,函数可以操纵它所获得的参数
评估它们,并且可以决定同等地处理这两种情况,这显然是library
所做的。
以下是如何操作未评估表达式的示例:
> f <- function(x) match.call() # return unevaluated function call
> x <- f(foo)
> x
f(x = foo)
> mode(x)
[1] "call"
> x[[1]]
f
> x[[2]]
foo
> mode(x[[2]])
[1] "name"
> as.character(x[[2]])
[1] "foo"
> x <- f("foo")
> mode(x[[2]])
[1] "character"