Don*_*nen 27 r function ellipsis
我无法理解括号如何/为什么在它们不应该起作用的地方起作用\xc2\xae。
\nf = function(...) substitute(...()); f(a, b)\n[[1]]\na\n[[2]]\nb\n# but, substitute returns ..1\nf2 = function(...) substitute(...); f2(a, b)\na\nRun Code Online (Sandbox Code Playgroud)\n通常会抛出错误,找不到在不正确的上下文中使用的函数“...”或\'...\' ,例如在调用时(\\(...) ...())(5)。
我尝试过的\
n我查看了源代码以substitute找出为什么这里不会发生这种情况。R 内部1.1.1 和 1.5.2 表示...是 SEXPTYPE DOTSXP,一对承诺列表。这些承诺是由 提取的substitute。
# \\-substitute #R\n# \\-do_substitute #C\n# \\-substituteList #C recursive\n# \\-substitute #C\nRun Code Online (Sandbox Code Playgroud)\n逐行进行,我陷入了困境substituteList,其中h是当前正在处理的元素...。这在第 2832 行递归发生if (TYPEOF(h) == DOTSXP) h = substituteList(h, R_NilValue);。我没有...()在源代码中找到案例的异常处理,所以我怀疑在此之前发生了什么。
在?substitute我们发现纯粹词汇基础上的替代作品。这是否意味着...()这是一个解析器技巧?
parse(text = "(\\\\(...) substitute(...()))(a, b)") |> getParseData() |> subset(text == "...", select = c(7, 9))\n\n#> token text\n#> 4 SYMBOL_FORMALS ...\n#> 10 SYMBOL_FUNCTION_CALL ...\nRun Code Online (Sandbox Code Playgroud)\n第二个省略号在词法分析期间被识别为函数调用的名称。它不像|>以前那样有自己的令牌。输出是一个对列表 ( typeof(f(a, b))) ,在本例中与常规列表(?)相同。我想这不是解析器技巧。但不管它是什么,它已经存在了一段时间了!
问题:
\n如何...()工作?
Mik*_*gan 22
注意:在参考文档和源代码时,我提供了R官方Subversion 存储库的非官方 GitHub 镜像的链接。这些链接绑定到 GitHub 存储库中的提交 97b6424 ,该链接映射到 Subversion 存储库中的修订版(本次编辑时的最新版本)。 81461
substitute是一个“特殊”,其参数不被评估(doc)。
typeof(substitute)\nRun Code Online (Sandbox Code Playgroud)\n[1] "special"\nRun Code Online (Sandbox Code Playgroud)\n这意味着 的返回值substitute可能与解析器逻辑不一致,具体取决于内部处理未评估参数的方式。
通常,以(伪代码) (doc )形式substitute接收调用。调用的上下文决定了如何处理。具体来说, if在函数内部被调用并作为形式参数...(<exprs>)LANGSXPpairlist(R_DotsSymbol, <exprs>)substituteSYMSXP R_DotsSymbolsubstitute...rho作为其执行环境,则结果为
findVarInFrame3(rho, R_DotsSymbol, TRUE)\nRun Code Online (Sandbox Code Playgroud)\nsubstituteList在 C 实用程序( source )的主体中是 aDOTSXP或R_MissingArg\xe2\x80\x94,后者当且仅当在f不带参数的情况下调用 ( doc )。在其他上下文中,结果是R_UnboundValueor (例外)其他一些SEXP\xe2\x80\x94,后者当且仅当一个值绑定到...中的名称时rho。每一个案件都由 专门处理substituteList。
处理的多样性R_DotsSymbol是这些 R 语句给出不同结果的原因:
f0 <- function() substitute(...(n = 1)); f0()\n## ...(n = 1)\nf1 <- function(...) substitute(...(n = 1)); f1()\n## $n\n## [1] 1\ng0 <- function() {... <- quote(x); substitute(...(n = 1))}; g0()\n## Error in g0() : \'...\' used in an incorrect context\ng1 <- function(...) {... <- quote(x); substitute(...(n = 1))}; g1()\n## Error in g1() : \'...\' used in an incorrect context\nh0 <- function() {... <- NULL; substitute(...(n = 1))}; h0()\n## $n\n## [1] 1\nh1 <- function(...) {... <- NULL; substitute(...(n = 1))}; h1()\n## $n\n## [1] 1\nRun Code Online (Sandbox Code Playgroud)\n考虑到如何...(n = 1)解析,您可能期望f1return call("...", n = 1)、bothg0和g1return call("x", n = 1)、bothh0和h1抛出错误,但由于上述原因,情况并非如此,主要是未记录的原因。
当在 R 函数内部调用时f,
f <- function(...) substitute(...(<exprs>))\nRun Code Online (Sandbox Code Playgroud)\nsubstitute评估对 C 实用程序do_substitute\xe2\x80\x94 的调用,您可以通过查看此处\xe2\x80\x94 来了解这一点,其中argList获取LISTSXP形式的 a pairlist(x, R_MissingArg),其中x是LANGSXP形式的 a pairlist(R_DotsSymbol, <exprs>)(源)。
如果你关注 的正文,那么你会发现传递给fromdo_substitute的值是 a的形式( source )。tsubstituteListdo_substituteLISTSXPpairlist(copy_of_x)
由此可见,调用 ( sourcewhile )内部的循环恰好有一次迭代,并且循环 ( source )主体中的语句是substituteListCAR(el) == R_DotsSymbolfalse位于该迭代中。
在false条件分支 ( source ) 中,h获取值\n pairlist(substituteList(copy_of_x, env))。循环退出并substituteList返回h到do_substitute,后者又返回CAR(h)到 R (源1 , 2 , 3)。
因此, 的返回值substitute是substituteList(copy_of_x, env),并且仍然需要推断出 this 的身份SEXP。在对的调用内部substituteList,while循环进行了1+m迭代,其中m是 的数量<exprs>。CAR(el) == R_DotsSymbol在第一次迭代中,循环体中的语句是true是。
在true条件分支 ( source ) 中,h是 aDOTSXP或R_MissingArg,因为fhas...作为形式参数 ( doc )。继续,你会发现substituteList返回:
R_NilValue如果h是R_MissingArg在第一次while迭代中并且 m = 0,或者,否则,
\nLISTSXP中的表达式,后跟(if ),全部未计算且没有替换,因为 的执行环境在调用时为空。hhDOTSXPwhile<exprs>m > 1fsubstitute的确:
\nf <- function(...) substitute(...())\nis.null(f())\n## [1] TRUE\nf <- function(...) substitute(...(n = 1))\nidentical(f(a = sin(x), b = zzz), pairlist(a = quote(sin(x)), b = quote(zzz), n = 1))\n## [1] TRUE\nRun Code Online (Sandbox Code Playgroud)\nFWIW,它帮助我在添加一些打印语句到coerce.c. 例如,我之前在( sourceUNPROTECT(3); )的正文中添加了以下内容:do_substitute
Rprintf("CAR(t) == R_DotsSymbol? %d\\n",\n CAR(t) == R_DotsSymbol);\n if (TYPEOF(CAR(t)) == LISTSXP || TYPEOF(CAR(t)) == LANGSXP) {\n Rprintf("TYPEOF(CAR(t)) = %s, length(CAR(t)) = %d\\n",\n type2char(TYPEOF(CAR(t))), length(CAR(t)));\n Rprintf("CAR(CAR(t)) = R_DotsSymbol? %d\\n",\n CAR(CAR(t)) == R_DotsSymbol);\n Rprintf("TYPEOF(CDR(CAR(t))) = %s, length(CDR(CAR(t))) = %d\\n",\n type2char(TYPEOF(CDR(CAR(t)))), length(CDR(CAR(t))));\n }\n if (TYPEOF(s) == LISTSXP || TYPEOF(s) == LANGSXP) {\n Rprintf("TYPEOF(s) = %s, length(s) = %d\\n",\n type2char(TYPEOF(s)), length(s));\n Rprintf("TYPEOF(CAR(s)) = %s, length(CAR(s)) = %d\\n",\n type2char(TYPEOF(CAR(s))), length(CAR(s)));\n }\nRun Code Online (Sandbox Code Playgroud)\n这帮助我确认了上一行的通话内容substituteList:
f <- function(...) substitute(...(n = 1))\ninvisible(f(hello, world, hello(world)))\nRun Code Online (Sandbox Code Playgroud)\nCAR(t) == R_DotsSymbol? 0\nTYPEOF(CAR(t)) = language, length(CAR(t)) = 2\nCAR(CAR(t)) = R_DotsSymbol? 1\nTYPEOF(CDR(CAR(t))) = pairlist, length(CDR(CAR(t))) = 1\nTYPEOF(s) = pairlist, length(s) = 1\nTYPEOF(CAR(s)) = pairlist, length(CAR(s)) = 4\nRun Code Online (Sandbox Code Playgroud)\ninvisible(substitute(...()))\nRun Code Online (Sandbox Code Playgroud)\nCAR(t) == R_DotsSymbol? 0\nTYPEOF(CAR(t)) = language, length(CAR(t)) = 1\nCAR(CAR(t)) = R_DotsSymbol? 1\nTYPEOF(CDR(CAR(t))) = NULL, length(CDR(CAR(t))) = 0\nTYPEOF(s) = pairlist, length(s) = 1\nTYPEOF(CAR(s)) = language, length(CAR(s)) = 1\nRun Code Online (Sandbox Code Playgroud)\n显然,使用调试符号编译 R 并在调试器下运行 R 也有帮助。
\n刚刚注意到这个奇怪的现象:
\ng <- function(...) substitute(...(n = 1), new.env())\ngab <- g(a = sin(x), b = zzz)\ntypeof(gab)\n## [1] "language"\ngab\n## ...(n = 1)\nRun Code Online (Sandbox Code Playgroud)\n这里有人可以进行另一次深入研究,以找出当您提供不同于(包括)时结果是 aLANGSXP而不是 a的原因。LISTSXPenvenvironment()env = NULL