有没有办法检查 Rcpp::Function 的数量?
Is there a way to check the arity of Rcpp::Function?
我需要在 运行 时间检查 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 的元数的函数。有什么办法吗?
“有限的文档”(目前只有 10 个 pdf 小插图)告诉您,除其他外,我们从 R 本身得到的只是 .Call()
返回 SEXP
并获取(任意数量的) SEXP
个可以是函数的对象。所以所有这一切......回到 R API 它可能有也可能没有这样的访问器,它可能是也可能不是 public 并且应该供除 R 本身以外的任何人使用。
这些天我们用 R 注册编译函数(通常在文件 src/init.c
或类似文件中),其中这个参数数量 作为第二个参数传递给 (超出函数调用名称)进行注册时。这对我来说表明它是不可发现的。
所以我使用了一个有点笨拙的解决方法解决了这个问题,但在认真考虑之后,这是我尝试实施的三种方法中最不笨拙的。
我最终采用的方法是使用 methods::formalArgs
检查 R 端函数的元数,将 (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
传递给 loglikelihood
并在我们需要使用它之前查询它,但我认为这种方法是三种方法中最笨拙的,因为它需要我们经常通过 formalArgs
。
我需要在 运行 时间检查 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 的元数的函数。有什么办法吗?
“有限的文档”(目前只有 10 个 pdf 小插图)告诉您,除其他外,我们从 R 本身得到的只是 .Call()
返回 SEXP
并获取(任意数量的) SEXP
个可以是函数的对象。所以所有这一切......回到 R API 它可能有也可能没有这样的访问器,它可能是也可能不是 public 并且应该供除 R 本身以外的任何人使用。
这些天我们用 R 注册编译函数(通常在文件 src/init.c
或类似文件中),其中这个参数数量 作为第二个参数传递给 (超出函数调用名称)进行注册时。这对我来说表明它是不可发现的。
所以我使用了一个有点笨拙的解决方法解决了这个问题,但在认真考虑之后,这是我尝试实施的三种方法中最不笨拙的。
我最终采用的方法是使用 methods::formalArgs
检查 R 端函数的元数,将 (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
传递给 loglikelihood
并在我们需要使用它之前查询它,但我认为这种方法是三种方法中最笨拙的,因为它需要我们经常通过 formalArgs
。