Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Call R function from C wrapper

Tags:

r

I have a function like so:

callFunc <- function (f) {
    f(1)
}

f could be (for example) f <- function (x) x. To simplify things, let's say that I know that f should return a numeric and take in a single numeric.

I'd like to move callFunc to C, but still have the function f defined in R, i.e.

.Call('callFunc', function (x) x)

I'm struggling with how to evaluate my callback on the C side. I have it like this at the moment:

#include <R.h>
#include <Rdefines.h>

SEXP callFunc (SEXP i_func) {
    return i_func(1);
}

(Then to test it:

R CMD SHLIB test.c
# then in R
dyn.load('test.so'); .Call('callFunc', function (x) x)

)

Of course, the above does not work because

  • I have not coerced i_func into the appropriate closure form; I'm not sure how to do this (there are AS_foo macros in Rdefines.h, but no AS_CLOSURE).
  • I haven't even told the C code that i_func should take in a numeric and return a numeric, so how can it even evaluate?

Could anyone give me pointers on how to go about doing this? I'm working my way through writing R extensions but this is rather long and I haven't found what I'm after yet. Also there is this question on R-help but the answer looks like they implemented the callback f in C as well, rather than leaving it as an R object.

like image 452
mathematical.coffee Avatar asked May 06 '14 07:05

mathematical.coffee


People also ask

How do you call a function in c in R?

Calling C functions from R Call is to use . External . It is used almost identically, except that the C function will receive a single argument containing a LISTSXP , a pairlist from which the arguments can be extracted. This makes it possible to write functions that take a variable number of arguments.

Does R use c?

So in conclusion: while R itself is mostly written in C (with hefty chunks in R and Fortran), R packages are mostly written in R (with hefty chunks written in C/C++).

What is a wrapper R?

As the name implies, a wrapper function is just a function which wraps another function. Maybe inside it does something like set some default values for parameters, etc.


2 Answers

This is very easy with Rcpp:

Rcpp::cppFunction("SEXP callFun(Function f) {
  return f(1);
}")

callFun(function(x) x + 10)
# [1] 11
like image 137
hadley Avatar answered Oct 24 '22 04:10

hadley


For completeness, here is how you'd do it without Rcpp (I took my cue from the XML package, which lets you provide handlers). You construct a call (first argument is the function as a SEXP, subsequent arguments are the function arguments, all SEXP) and use 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);              
}   

From R:

.Call('callFunc', function (x) sin(x))
like image 31
mathematical.coffee Avatar answered Oct 24 '22 02:10

mathematical.coffee