Rcpp11 / rjournal_article

C++11 Article for the R journal
1 stars 0 forks source link

The addition of lambda functions #4

Open kevinushey opened 10 years ago

kevinushey commented 10 years ago

One of the main things that I think many people like in R is how easy it is to define and use anonymous functions, e.g. in sapply, lapply, Reduce, Map, and so on. The addition of lambda functions in C++11 makes this possible with C++ and so I think it deserves a spot.

I think parallels that can be drawn between programming R and C++11, ie, features of C++11 that sort of feel like 'R with types' would be a good fit.

romainfrancois commented 10 years ago

Yes. And there are things in the api that benefit from lambdas:

// [[Rcpp::export]]
NumericVector dist(NumericVector x_, NumericVector y_){
    return mapply( x_, y_, [](double x, double y){ 
        return pow( (x-y), 2.0 ) ;
    } ); 
}

Whereas with Rcpp we would have needed to name the worker function.

There currently is no Reduce but it should be fairly easy to come up with it, e.g. here is an initial version :

template <class Vec, class Fun>
class Reducer {
public:
    typedef typename Vec::stored_type T ;
    typedef typename std::result_of<Fun(T,T)>::type output; 

    Reducer( const Vec& data_, Fun fun_) : data(data_), fun(fun_){}

    operator T(){
        T start = data[0] ;
        return std::accumulate( data.begin()+1, data.end(), start, fun ) ;
    }

private:
    const Vec& data; 
    Fun fun ;
} ;

template <typename Vec, typename Fun>
inline Reducer<Vec,Fun> Reduce( const Vec& vec, Fun fun){
    return Reducer<Vec,Fun>( vec, fun ) ;
}

// [[Rcpp::export]]
double test_reduce( NumericVector x){
    return Reduce( x, [](double x, double y){ return x+y ; } ) ;    
}

/*** R
    test_reduce( seq(1,10) )
    # [1] 55
*/
romainfrancois commented 10 years ago

Now talking about lambdas in the current version of the paper. Fits well in the current theme of the article.

romainfrancois commented 10 years ago

Another thing lambda gives us is a better way to handle try/catch. In the context branch of Rcpp11, we can do this:

void test(){
  Language call( "stop", "boom") ;
  try_catch( [&](){
      Rf_eval(call, R_GlobalEnv) ;
  })
  Rprintf( "hello\n") ;
)

The idea is that the code inside the lamda is guaranteed not to long jump outside of the try_catch, so we don't have to do the wrapping in an R tryCatch which has always been expensive.