Search code examples
c++rrcpp

How to pass in functions as arguments in Rcpp / C++?


I'm trying to write a function which can take in functions as its arguments in Rcpp. I have written an example function in R that shows the kind of functionality that I'm aiming for:

simulate_and_evaluate <- function(simulate, evaluate) {
  y <- simulate(1)
  eval <- evaluate(y)
  return(eval)
}

simulate_fun <- function(n) rnorm(n, 0, 1)
evaluate_fun <- function(x) dnorm(x, 0, 1)

simulate_and_evaluate(simulate = simulate_fun,
                      evaluate = evaluate_fun)

In this function simulate_and_evaluate, this takes in two arguments which are both functions, one that simulates a number and one that evaluates a function with this simualted number. So as an example, we can simulate a value from a standard normal and evaluate the density of a standard normal at that point. Does anyone know if there's a way to do this in Rcpp?


Solution

  • Rcpp aims for seamless interfacing of R and C++ objects. As functions are first class R objects represented internally as a type a SEXP can take, we can of course also ship them with Rcpp. There are numerous examples.

    So here we simply rewrite your function as a C++ function:

    Rcpp::cppFunction("double simAndEval(Function sim, Function eval) {
      double y = as<double>(sim(1));
      double ev = as<double>(eval(y));
      return(ev);
    }")
    

    And we can then set the RNG to the same value, run your R function and this C++ function and get the same value. Which is awesome.

    R> set.seed(123)
    R> simulate_and_evaluate(simulate = simulate_fun,
    + evaluate = evaluate_fun)
    [1] 0.341
    R> set.seed(123) # reset RNG
    R> simAndEval(simulate_fun, evaluate_fun)
    [1] 0.341
    R> 
    

    But as @MrFlick warned you, this will not run any faster because we added no compiled execution of the actual functions we are merely calling them from C++ rathern than R.

    The topic has been discussed before. Please search StackOverflow, maybe with a string [rcpp] Function to get some meaningful hits.