0

我需要在运行时检查 Rcpp 块中函数的数量。我想做的是类似于以下内容:

double loglikelihood(Rcpp::List data, Rcpp::List params, SEXP i, Rcpp::RObject custom_function) {
    Rcpp::Function f = Rcpp::as<Rcpp::Function>(custom_function);
    double res = 0.0;
    if (arity(f) == 3) {
        res = Rcpp::as<double>(f(data, param, i));
    } else if (arity(f) == 2) {
        res = Rcpp::as<double>(f(data, param));
    }
    return res;
}

但是,我看到的有关 Rcpp 的有限文档似乎不包含用于检查 Rcpp::Function 的元数的函数。有没有办法做到这一点?

4

2 回答 2

1

“有限的文档”(目前仅 10 个 pdf 小插图)告诉您,除其他外,我们从 R 本身获得的只是.Call()返回SEXP和获取(任意数量)SEXP可以是函数的对象。所以这一切......回到R API,它可能有也可能没有这样的访问器,它可能是公共的,也可能不是公共的,并且应该由R本身以外的任何人使用。

这些天来,我们用 R 注册编译函数(通常在文件src/init.c或类似文件中),其中这个数量的参数在注册时作为第二个参数(除了函数调用名称)传递。这向我表明它是不可发现的。

于 2021-01-14T15:22:37.323 回答
0

因此,我使用一种有点笨拙的解决方法解决了这个问题,但经过认真考虑后,这是我尝试实施的三种方法中最不笨拙的一种。

我最终采用的方法是检查 R 端函数的methods::formalArgsarity ,将 (function, arity) 对包装在一个列表中,并将其传递给 Rcpp 函数,如下所示:

double loglikelihood(Rcpp::List data, Rcpp::List params, 
                     SEXP i, Rcpp::RObject custom_function) {
    Rcpp::List l = Rcpp::as<Rcpp::List>(custom_function);
    Rcpp::Function f = Rcpp::as<Rcpp::Function>(l[0]);
    int arity = l[1];

    double res = 0.0;
    if (arity == 3) {
        res = Rcpp::as<double>(f(data, param, i));
    } else if (arity == 2) {
        res = Rcpp::as<double>(f(data, param));
    }
    return res;
}

正如我所提到的,这有点笨拙,它改变了函数的签名,这并不理想。另一种方法是使用宽恕而不是许可方法并在 try-catch 块中执行控制流,如下所示:

double loglikelihood(Rcpp::List data, Rcpp::List params, 
                     SEXP i, Rcpp::RObject custom_function) {

    Rcpp::Function f = Rcpp::as<Rcpp::Function>(custom_function);

    double res = 0.0;
    try {
        res = Rcpp::as<double>(f(data, param, i));
    } catch (const std::exception &e) {
        res = Rcpp::as<double>(f(data, param));
    }
    return res;
}

这种方法不那么笨重,但它的问题是它还捕获了可能在其中出现的其他异常f并将它们静音,因此它们不会传递给用户。有可能在 Rcpp 中定义了更细粒度的异常,它们能够捕获传递太多参数的特定错误,但如果是这样我还没有找到。

最后,我们可以在我们需要使用它之前传递并查询它,但我认为这种方法是三种方法中最笨拙的,因为它需要我们传递methods::formalArgs很多。loglikelihoodformalArgs

于 2021-01-27T10:07:32.990 回答