我有这样的功能:
callFunc <- function (f) {
f(1)
}
f
可能是(例如)f <- function (x) x
。为简化起见,我们说我知道f应该返回一个数字并接受一个数字。
我希望将callFunc
移至C,但仍然在R中定义函数f
,即
.Call('callFunc', function (x) x)
我在如何评估C方面的回调方面苦苦挣扎。 我现在就是这样的:
#include <R.h>
#include <Rdefines.h>
SEXP callFunc (SEXP i_func) {
return i_func(1);
}
(然后测试一下:
R CMD SHLIB test.c
# then in R
dyn.load('test.so'); .Call('callFunc', function (x) x)
)
当然,上述方法不起作用,因为
i_func
进入适当的封闭形式;我不确定如何执行此操作(AS_foo
中有Rdefines.h
个宏,但没有AS_CLOSURE
。i_func
应该接受一个数字并返回一个数字,那么它怎么能评估呢?有人能指点我怎么做吗?
我正在writing R extensions工作,但这已经很长了,我还没有找到我之后的事情。还有this question on R-help,但答案看起来他们也在C中实现了回调f
,而不是将其作为R对象。
答案 0 :(得分:3)
使用Rcpp非常容易:
Rcpp::cppFunction("SEXP callFun(Function f) {
return f(1);
}")
callFun(function(x) x + 10)
# [1] 11
答案 1 :(得分:1)
为了完整起见,这里是你如何在没有Rcpp的情况下做到这一点(我从XML包中获取了提示,它允许你提供处理程序)。您构造一个调用(第一个参数是函数作为SEXP,后续参数是函数参数,所有SEXP)并使用eval
。
// takes a callback and evaluates it (with argument 1), returning the result.
SEXP callFunc(SEXP func) {
SEXP call, ans;
PROTECT(call = allocVector(LANGSXP, 2)); // call + arg
SEXP c;
c = call;
SETCAR(call, func);
c = CDR(c);
// for some reason if I just SETCDR(c, ScalarReal(1.0)) I get
// a memory fault, but using SETCAR like this is fine.
SETCAR(c, ScalarReal(1.0));
ans = eval(call, R_GlobalEnv); // maybe PROTECT?
UNPROTECT(1);
return(ans);
}
来自R:
.Call('callFunc', function (x) sin(x))