在Hadley的《 Advanced R 2nd ed》一书的元编程部分中,我很难理解这个概念。我已经用R编程了一段时间,但这是我第一次遇到元编程的概念。这个练习题尤其使我感到困惑
“以下两个调用打印相同,但实际上不同:
(a <- expr(mean(1:10)))
#> mean(1:10)
(b <- expr(mean(!!(1:10))))
#> mean(1:10)
identical(a, b)
#> [1] FALSE
有什么区别?哪一个更自然?”
当我评估它们时,它们都返回相同的结果
> eval(a)
[1] 5.5
> eval(b)
[1] 5.5
当我在a和b对象内部查看时,第二个对象的打印确实不同,但是我不确定这两个对象之间的区别是什么
> a[[2]]
1:10
> b[[2]]
[1] 1 2 3 4 5 6 7 8 9 10
如果我只是在没有eval(expr(...))的情况下运行它们,那么它将返回不同的结果:
mean(1:10)
[1] 5.5
mean(!!(1:10))
[1] 1
我的猜测是,没有expr(...)!!(1:10)会起到双重否定的作用,在强制作用下,强制所有数字均为1,因此均值为1。
我的问题是:
为什么!有和没有expr(...)的行为都不同?我希望eval(expr(mean(!!(1:10))))返回的结果与mean(!!(1:10))相同,但这不是
我仍然不太完全了解一个对象和b个对象之间的区别是什么?
先谢谢您
答案 0 :(得分:0)
这是区别。当我们取反(!
)整数向量时,非0的数字将转换为FALSE,而0将转换为TRUE。与另一个否定即。 double(!!
),则将FALSE更改为TRUE,反之亦然
!0:5
#[1] TRUE FALSE FALSE FALSE FALSE FALSE
!!0:5
#[1] FALSE TRUE TRUE TRUE TRUE TRUE
以OP的示例为准,TRUE
!!1:10
#[1] TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE TRUE
和TRUE / FALSE可以为1/0
as.integer(!!1:10)
#[1] 1 1 1 1 1 1 1 1 1 1
因此mean
为1
mean(!!1:10)
#[1] 1
关于'a'与'b'
str(a)
#language mean(1:10)
str(b)
#language mean(1:10)
两者都是语言对象,将对其进行评估以获得数字1:10的mean
all.equal(a, b)
#[1] TRUE
如果我们需要获得10个数字的mean
,则第一个是正确的方法。
我们可以eval
正确地设置第二个选项,即通过mean
设置
quote
的值1。
eval(quote(mean(!!(1:10))))
#[1] 1
eval(quote(mean(1:10)))
#[1] 5.5
答案 1 :(得分:0)
!!
在这里不是双重否定,而是rlang
中的unquote运算符。
取消引用是引用的一种逆向。它允许您有选择地 评估expr()中的代码,使expr(!! x)等效于x。
a
和b
之间的区别是,该参数在a
中作为未评估的调用保留在b
中:
class(a[[2]])
[1] "call"
class(b[[2]])
[1] "integer"
a
行为在某些情况下可能是有利的,因为它会延迟评估,或者由于相同的原因而不利。如果这是一个缺点,那就是造成极大挫败感的原因。如果参数是一个较大的向量,则b
的大小将增加,而a
的大小将保持不变。
有关更多详细信息,请参见section 19.4 of Advanced R。
答案 2 :(得分:0)