在函数中调用 print(ls.str()) 会影响 rep 的行为

Calling print(ls.str()) in function affect behavior of rep

在空环境中开始新的 R 会话。编写一系列函数,其参数将用作调用 rep().

times 参数的值
f <- function(n) {
  rep("hello", times = n)
}
f(x)

有人认为这会失败,但确实有人得到:

# Error in f(x) : object 'x' not found

稍微修改一下函数:

f2 <- function(n) {
  ls.str()
  rep("hello", times = n)
}

f2(x)

不出所料,还是失败了:

# Error in f2(x) : object 'x' not found

再修改一点(在控制台查看环境):

f3 <- function(n) {
  print(ls.str())
  rep("hello", times = n)
}

f3(x)

我仍然期望失败,而是得到:

## n : <missing>
## [1] "hello"

就好像对 print() 的调用使 rep 像 times 设置为 1 一样工作。

f4 <- function(n) {
  print('test')
  print(ls.str())
  print('end test')
  rep("hello", times = n)
}
f4(x)

## [1] "test"
## n : <missing>
## [1] "end test"
## [1] "hello"

print.ls_str 中有问题,从 Frank 的聊天测试来看,以下代码显示出同样的问题:

f6 <- function(n) {
  z = tryCatch(get("n", new.env(), mode = "any"), error = function(e) e)
  rep("A", n)
}

深入挖掘 R 源代码,我发现 following code

#     define GET_VALUE(rval)                      \
    /* We need to evaluate if it is a promise */  \ 
    if (TYPEOF(rval) == PROMSXP) {                \
        PROTECT(rval);                            \
        rval = eval(rval, genv);                  \
        UNPROTECT(1);                             \
    }                                             \
                                                  \
    if (!ISNULL(rval) && NAMED(rval) == 0)        \
        SET_NAMED(rval, 1)


    GET_VALUE(rval);
    break;


    case 2: // get0(.)
    if (rval == R_UnboundValue)
        return CAD4R(args);// i.e.  value_if_not_exists
    GET_VALUE(rval);
    break;
    }
    return rval;
}
#undef GET_VALUE

我很惊讶这个编译正确,据我所知(我的 C 远远落后)#define 不允许在 # 和定义。

经过挖掘,我错了,来自 gcc doc:

Whitespace is also allowed before and after the `#'.

所以这部分代码可能有一些东西,但我无法确定到底是什么。

这不是答案,但太长 post 作为评论。一个最小的可重现示例是:

f3 <- function(n) {
  try(get("n", environment(), inherits=FALSE))
  rep("hello", times = n)
}
f3(x)
## Error in get("n", environment(), inherits = FALSE) : object 'x' not found
## [1] "hello"

以下内容是推测性的,基于对 do_rep 的来源的粗略检查。 get 开始 promise 评估,但在找不到 "missing" 符号时似乎使 promise 部分未评估。 rep,作为一个原语,然后尝试对 n 进行操作,但没有意识到这是一个部分评估的承诺,基本上这隐含地导致了 'n == 1'.

的假设

此外,这表明 promise 处于一种奇怪的状态(必须使用 browser/debug 才能看到):

f3a <- function(n) {
  try(get("n", environment(), inherits=FALSE))
  browser()
  rep("hello", times = n)
}
f3a(x)
## Error in get("n", environment(), inherits = FALSE) : object 'x' not found
## Called from: f3a(x)
# Browse[1]> (n)
## Error: object 'x' not found
## In addition: Warning message:
## restarting interrupted promise evaluation 
## Browse[1]> c
## [1] "hello"

我今天早些时候收到一份报告,该错误已在 R-devel 和 R-patched 中得到修复。

问题是 R 源中的缺失测试没有考虑中断的情况 promise evaluation. A fix has been committed by Luke Tierney and can be seen on GitHub