非标准评估的危险在哪里,如果有的话,是否有记录?

20
许多具有非标准评估的R函数,例如withsubsettransform,包含以下警告:
对于交互式使用,这非常有效且易于阅读。但是,在编程中,即在一个人的函数中,需要更加小心,通常应避免使用with(),因为数据中的变量可能会意外覆盖局部变量,请参见参考文献。(引用自with的文档,其他信息较少)
“参考文献”是2003年的这篇文章。坦白地说,我看不出它的相关性。它在第6节中提到了“数据中的变量可能会意外覆盖局部变量”的观点,但它只是提到了它。就我所知,那篇文章没有告诉你任何警告你检查参考文献时没有告诉你的内容。
我已经搜索了R手册,甚至在3500页的参考索引中搜索了“非标准”一词,但除了我已经提到的内容之外,我没有找到其他任何东西。我真的以为它会在语言定义中,但我已经阅读了整个内容,没有找到它。我最接近的是涵盖substitute函数的部分,我知道很多具有非标准评估的函数都依赖于它。
至于任何其他我确信无法找到帮助的地方,我已经从头到尾阅读了R FAQR入门指南。 R FAQ仅在几次中提到evalsubstitute,但与此无关。唯一值得一提的是这里,它还建议检查deriv的文档,但我在那里找不到有用的内容。
那么,R的官方文档中有关于非标准评估危险的官方部分吗?我发现R文档的某些部分会告诉我要小心某些东西,但没有提供任何告诉我如何做到这一点的地方。毫无疑问,需要小心谨慎。例如,Advanced R展示了几种具有非标准评估功能的函数可能会引起问题。我以前曾因此粗心而付出代价,很容易找到优秀答案,其中包含有关非标准评估的警告评论。

1
只是一个跟进:从我找到的资料来看,也许答案在于R语言严重基于S编程语言(特别是S-PLUS版本和白皮书版本),而后者受到LISP的极大启发。也许非标准评估在S文档中有更详细的介绍?但是,我没有找到任何合理易读或免费的文档介绍它。 - eduardokapp
1
@eduardokapp R和S不共享相同的作用域规则。根据我在其他地方阅读到的内容,非标准评估的主要问题之一是它如何找到所调用的参数。假设S具有完全不同的作用域规则,则它不能以与R相同的方式工作来解决该问题。 - J. Mini
2
现在我们接近赏金结束,高数量的赞许给我强烈的印象,答案是“它们没有被记录在任何地方”。遗憾。 - J. Mini
@eduardokapp 你可以查看以下关于S-PLUS的链接,但正如我已经说过的,我怀疑你会找到任何相关的内容:https://www2.stat.duke.edu/courses/Fall99/sta240/PGUIDE.PDF - J. Mini
2个回答

4
(作为回答发布,因为这段内容有点长了。) 我不知道有没有一个特定的地方记录危险性,但是根据我的个人经验,在使用 NSE 时需要注意两个重要注意事项:
  1. substitute() 在嵌套函数中不能正常工作,这会导致在尝试对使用 substitute() 的函数进行复杂操作时出现问题。例如包括glm()coxph()

  2. 如果使用 rlang,则运算符 !! 会导致其操作数相对于整个表达式进行 立即评估。如果表达式包含将在评估其他部分表达式时定义的变量,则可能会导致晦涩的“找不到变量”错误。

除了这两个注意事项之外,我通常认为 NSE 非常健壮。特别是如果您使用的是 rlang,它可以大大规范 NSE 功能。尽管如此,我的个人建议是只在必要时使用 NSE,并尽可能坚持使用标准评估(SE)。尽管 NSE 可能非常强大,但会产生难以阅读、理解和维护的代码。

2
我猜 R 语言定义的第 6.3 "关于评估的更多内容" 部分对整个问题有所提及。
引用部分如下:
“另一个经常出现的情况是在列表或数据框中进行评估。例如,在给定数据参数时,这会发生在 model.frame 函数中。通常,模型公式中的术语需要在数据中进行评估,但它们偶尔也可能包含对 model.frame 的调用者中的项目的引用。这在模拟研究中有时很有用。因此,为了达到这个目的,不仅需要在列表中评估表达式,还需要指定一个封闭空间,以便在列表中没有找到变量时继续搜索。因此,该调用的形式为 eval(expr, data, sys.frame(sys.parent()))。”
然后是文本中似乎“警告”读者的具体部分:
注意,对于给定的环境进行评估可能会实际上改变该环境,最明显的情况是涉及赋值运算符的情况,例如eval(quote(total <- 0), environment(robert$balance)) # rob Rob。在评估列表时也是如此,但原始列表不会改变,因为实际上是在副本上操作。

也许它应该得到改进,因为它肯定不能直接涉及非标准评估。


1
我并不信服。你可能是正确的,但我非常怀疑。正如你所说,它间接地涉及了这个主题。它主要讨论了eval的可选参数,因此我们离谈论像with这样的函数还有三步之遥。引用的部分并没有谈论with,甚至没有谈论它所依赖的substitute函数:它主要是在谈论eval函数的可选参数,当你使用eval时,你_可能_会使用substitute,而你可能会使用它来构建像with这样的函数。这离问题太远了。 - J. Mini
2
我同意!我不确定是否有任何官方文件。我查阅了您提供的所有文档。真遗憾! - eduardokapp

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接