在函数外部工作但在 R 函数内部失败的参数
An argument working outside a function but fails inside a function in R
在函数外部时,下面的参数 pbkrtest.limit = nobs(m1)
工作正常(因此,不会生成任何消息)。
但是在foo()
函数内部时,nobs(m1)
无法识别(因此会生成一条消息)!我真的很想知道发生了什么事?
library(lme4)
library(emmeans)
dat <- read.csv('https://raw.githubusercontent.com/hkil/m/master/z.csv')
m1 <- lmer(y~ year*group + (1|stid), data = dat)
## WORKS FINE:
emtrends(m1, pairwise ~ group, var = "year", infer = c(T, T), pbkrtest.limit = nobs(m1))
## BUT NOW `nobs(m)` doesn't work inside the function:
foo <- function(m){
emtrends(m, pairwise ~ group, var = "year", infer = c(T, T), pbkrtest.limit = nobs(m))
}
## RUN:
foo(m = m1)
尝试在 parent.frame 中评估它:
foo <- function(m, envir = parent.frame()) {
s <- substitute(emtrends(m, pairwise ~ group, var = "year", infer = c(TRUE, TRUE),
pbkrtest.limit = nobs(m)))
eval(s, envir)
}
foo(m = m1)
并通过 https://github.com/rvlenth/emmeans/issues
向开发人员报告
也使用 TRUE 而不是 T,因为 T 可以被覆盖但 TRUE 不能。
我根据 emtrends()
中的实际代码更仔细地研究了这一点。它归结为以下代码中演示的内容:
# comparison of evaluation methods with lazy eval
# a trivial function
foo = function(x, ...)
x^2
# calls foo three ways
foodoo = function(...) {
message("x1 = ", foo(...))
message("x2 = ", do.call("foo", list(...)))
cl = match.call()
cl[[1]] = quote(foo)
message("x3 = ", eval(cl))
}
# test value
val = 3.5
# test runs
foodoo(x = 5)
## x1 = 25
## x2 = 25
## x3 = 25
foodoo(x = val)
## x1 = 12.25
## x2 = 12.25
## x3 = 12.25
# same tests, wrapped in a function...
bar = function(z) {
foodoo(x = z)
}
bar(5)
## x1 = 25
## x2 = 25
## Error in foo(x = z): object 'z' not found
bar(val)
## x1 = 12.25
## x2 = 12.25
## Error in foo(x = z): object 'z' not found
由 reprex package (v0.3.0)
于 2020-05-31 创建
OP 遇到的问题与第三种评估方法有关。在 emtrends()
中,代码匹配调用,将其修复以供不同的函数使用,然后对其求值。我不确定我是否完全理解所有这些,但是函数调用中传递的实际上是承诺,而不是值;一个 promose 由一个未计算的表达式和它应该被计算的环境组成。
在查看 foodoo()
时,似乎在使用前两种方法时,这些承诺会在调用 foo
之前更新到当前环境,而在第三种方法中,原始调用保持完好无损,这样承诺就不会改变。显然(我仍然不太清楚为什么),当我们从全局环境调用 foodoo()
时,那些原始环境已经足够好了,但从不同的环境调用时显然不够好。如果有人愿意发表评论和进一步解释,我洗耳恭听。
无论如何,我很高兴,因为我能够通过强制评估所有 ...
参数并将它们替换为 cl
:
来解决问题
# new foodoo
foodoo = function(...) {
message("x1 = ", foo(...))
message("x2 = ", do.call("foo", list(...)))
cl = match.call()
cl[[1]] = quote(foo)
dots = eval(list(...)) # added
cl[names(dots)] = dots # added
message("x3 = ", eval(cl))
}
bar(5)
## x1 = 25
## x2 = 25
## x3 = 25
bar(val)
## x1 = 12.25
## x2 = 12.25
## x3 = 12.25
在函数外部时,下面的参数 pbkrtest.limit = nobs(m1)
工作正常(因此,不会生成任何消息)。
但是在foo()
函数内部时,nobs(m1)
无法识别(因此会生成一条消息)!我真的很想知道发生了什么事?
library(lme4)
library(emmeans)
dat <- read.csv('https://raw.githubusercontent.com/hkil/m/master/z.csv')
m1 <- lmer(y~ year*group + (1|stid), data = dat)
## WORKS FINE:
emtrends(m1, pairwise ~ group, var = "year", infer = c(T, T), pbkrtest.limit = nobs(m1))
## BUT NOW `nobs(m)` doesn't work inside the function:
foo <- function(m){
emtrends(m, pairwise ~ group, var = "year", infer = c(T, T), pbkrtest.limit = nobs(m))
}
## RUN:
foo(m = m1)
尝试在 parent.frame 中评估它:
foo <- function(m, envir = parent.frame()) {
s <- substitute(emtrends(m, pairwise ~ group, var = "year", infer = c(TRUE, TRUE),
pbkrtest.limit = nobs(m)))
eval(s, envir)
}
foo(m = m1)
并通过 https://github.com/rvlenth/emmeans/issues
向开发人员报告也使用 TRUE 而不是 T,因为 T 可以被覆盖但 TRUE 不能。
我根据 emtrends()
中的实际代码更仔细地研究了这一点。它归结为以下代码中演示的内容:
# comparison of evaluation methods with lazy eval
# a trivial function
foo = function(x, ...)
x^2
# calls foo three ways
foodoo = function(...) {
message("x1 = ", foo(...))
message("x2 = ", do.call("foo", list(...)))
cl = match.call()
cl[[1]] = quote(foo)
message("x3 = ", eval(cl))
}
# test value
val = 3.5
# test runs
foodoo(x = 5)
## x1 = 25
## x2 = 25
## x3 = 25
foodoo(x = val)
## x1 = 12.25
## x2 = 12.25
## x3 = 12.25
# same tests, wrapped in a function...
bar = function(z) {
foodoo(x = z)
}
bar(5)
## x1 = 25
## x2 = 25
## Error in foo(x = z): object 'z' not found
bar(val)
## x1 = 12.25
## x2 = 12.25
## Error in foo(x = z): object 'z' not found
由 reprex package (v0.3.0)
于 2020-05-31 创建OP 遇到的问题与第三种评估方法有关。在 emtrends()
中,代码匹配调用,将其修复以供不同的函数使用,然后对其求值。我不确定我是否完全理解所有这些,但是函数调用中传递的实际上是承诺,而不是值;一个 promose 由一个未计算的表达式和它应该被计算的环境组成。
在查看 foodoo()
时,似乎在使用前两种方法时,这些承诺会在调用 foo
之前更新到当前环境,而在第三种方法中,原始调用保持完好无损,这样承诺就不会改变。显然(我仍然不太清楚为什么),当我们从全局环境调用 foodoo()
时,那些原始环境已经足够好了,但从不同的环境调用时显然不够好。如果有人愿意发表评论和进一步解释,我洗耳恭听。
无论如何,我很高兴,因为我能够通过强制评估所有 ...
参数并将它们替换为 cl
:
# new foodoo
foodoo = function(...) {
message("x1 = ", foo(...))
message("x2 = ", do.call("foo", list(...)))
cl = match.call()
cl[[1]] = quote(foo)
dots = eval(list(...)) # added
cl[names(dots)] = dots # added
message("x3 = ", eval(cl))
}
bar(5)
## x1 = 25
## x2 = 25
## x3 = 25
bar(val)
## x1 = 12.25
## x2 = 12.25
## x3 = 12.25