从C包装器调用R函数

时间:2014-05-06 07:14:17

标签: r

我有这样的功能:

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
  • 我甚至没有告诉C代码,i_func应该接受一个数字并返回一个数字,那么它怎么能评估呢?

有人能指点我怎么做吗? 我正在writing R extensions工作,但这已经很长了,我还没有找到我之后的事情。还有this question on R-help,但答案看起来他们也在C中实现了回调f,而不是将其作为R对象。

2 个答案:

答案 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))