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_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_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.
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.
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++).
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.
This is very easy with Rcpp:
Rcpp::cppFunction("SEXP callFun(Function f) {
return f(1);
}")
callFun(function(x) x + 10)
# [1] 11
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))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With