【问题标题】:Calling print(ls.str()) in function affect behavior of rep在函数中调用 print(ls.str()) 会影响 rep 的行为
【发布时间】:2018-02-27 00:57:00
【问题描述】:

使用空环境开始新的 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 一样工作。

【问题讨论】:

    标签: r rep


    【解决方案1】:

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

    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 开始对承诺进行评估,但在没有找到“缺失”符号时,似乎部分未评估承诺。 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"
    

    【讨论】:

    • 我已经可以只用rep 行重现代码,不需要try(get(…))。事实上,我认为do_rep 只是将其手动参数匹配错误,放弃了一个不存在的承诺,并假装除了x 之外的 no 参数已设置。关于“部分未评估”的承诺是一条红鲱鱼。
    • @KonradRudolph 我不关注。 f3a &lt;- function(n) rep("hello", times = n); f3a(x) 不会重现此内容。
    • @Roland Argh,确实如此。但是f3a() 可以。
    【解决方案2】:

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

    问题是 R 源中的缺失测试没有考虑中断promise evaluation 的情况。 Luke Tierney 修复了has been committed,可以看到on GitHub

    【讨论】:

    • 呃!现在接受,(对于 Stack Exchange 来说还是比较新的证明......)
    • @BrodieG,如果不先与 Big Dogs 确认,我绝不会涉足 R-devel-list 报告错误。因此我在这里发帖。
    【解决方案3】:
    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 的 chat 测试,下面的代码也出现了同样的问题:

    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 不允许在 # 和定义之间有空格。

    p>

    在挖掘之后,我错了,来自gcc doc

    “#”前后也允许有空格。

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

    【讨论】:

    • 我认为您的解释尝试太简单了。如果我使用f3 &lt;- function(n) { print(ls.str()); print(n); rep("hello", times = n) },我会收到有趣的警告:In print(n) : restarting interrupted promise evaluation。所以,显然print.ls.str 对承诺做了一些奇怪的事情。
    • @Roland 荷马·怀特似乎做到了:stat.ethz.ch/pipermail/r-devel/2017-September/074930.html
    • 是的,该错误已提交并修复。
    • @Homer 您可以自行回答,也可以在修复稳定版后更改标题(这是我在类似情况下所做的 stackoverflow.com/questions/30035939/…
    • 感谢@Frank 的建议,我接受了你的建议。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2020-01-05
    • 2021-08-18
    • 2019-10-11
    • 1970-01-01
    • 2018-12-23
    • 1970-01-01
    相关资源
    最近更新 更多