R语言 将未求值的表达式传递给C/C++

axkjgtzd  于 2023-05-04  发布在  C/C++
关注(0)|答案(2)|浏览(120)

我想从函数向C/C传递一个可变数量的参数,但希望不对参数求值,同时不想在R中进行任何计算(除了调用C/C函数)。我不想在R函数中调用substitute。我认为可以使用的一个选项是.External,并像这样执行smth:

R_fn = function(...) .External("cpp_fn", ...)

...
# and in C code:
SEXP cpp_fn (SEXP arglist) {
}

但是,.External正在计算...中的参数,因此如果我尝试类似

rm(x, y) # just making sure these don't exist

R_fn(x*y)

我得到一个错误,因为R试图在 * 将x*y * 发送到函数之前计算它。
下面的代码在R中工作:

f = function(...) g(...)
g = function(x, ...) print(substitute(x))

f(x*y*z)
# x * y * z

我还有其他选择吗?很明显,可以像R本身那样处理许多函数,例如。例如substitute本身,但我不知道如何做到这一点。我添加了rcpp标记,因为我最终会在Rcpp中使用它。

q3aa0525

q3aa05251#

一种可能性是做match.call所做的事情(感谢Ricardo Saporta为我指明了方向)。这需要从R源代码中复制粘贴一些定义,我在这里不会这样做,但基本思想是从R_GlobalContext中获取调用函数,然后从中提取函数参数。草图如下:

R_fn = function(...) .Call("cpp_fn")

// and in C++ code
Language cpp_fn() {
  SEXP sysp = ((RCNTXT*)R_GlobalContext)->sysparent;
  RCNTXT *cptr = (RCNTXT*)R_GlobalContext;

  while (cptr != NULL) {
    if (cptr->callflag & CTXT_FUNCTION && cptr->cloenv == sysp)
      break;
    cptr = cptr->nextcontext;
  }
  cptr = cptr->nextcontext; // because this is called from .Call and not from R_fn

  // and now cptr->promargs has the unevaluated arguments to do as one pleases
  // e.g.
  Language firstArg(R_PromiseExpr(CAR(cptr->promargs)));

  return firstArg;
}
i2loujxw

i2loujxw2#

我已经成功地使用了.External2接口,并在R Package 器的环境中查找了未评估的promise。没有彻底测试,但节省了我几百纳秒与交换了R级substitute()match.call()
在R中:

subs <- function(expr, ...) .External2(c_subs)

在C中:

#include <Rinternals.h>

SEXP c_subs(SEXP call, SEXP op, SEXP args, SEXP rho) {
    static SEXP R_ExprSymbol = NULL;
    if (R_ExprSymbol == NULL)
        R_ExprSymbol = Rf_install("expr");
    SEXP expr = Rf_findVar(R_ExprSymbol, rho); // Promise
    SEXP dots = Rf_findVar(R_DotsSymbol, rho); // Pairlist of promises
    return Rf_list2(PREXPR(expr), PREXPR(CAR(dots)));
}

相关问题