Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

higher level functions in R - is there an official compose operator or curry function?

I can create a compose operator in R:

 `%c%` = function(x,y)function(...)x(y(...))  

To be used like this:

 > numericNull = is.null %c% numeric  > numericNull(myVec)  [2] TRUE FALSE 

but I would like to know if there is an official set of functions to do this kind of thing and other operations such as currying in R. Largely this is to reduce the number of brackets, function keywords etc in my code.

My curry function:

> curry=function(...){     z1=z0=substitute(...);z1[1]=call("list");     function(...){do.call(as.character(z0[[1]]),                           as.list(c(eval(z1),list(...))))}} > p = curry(paste(collapse="")) > p(letters[1:10]) [1] "abcdefghij" 

This is especially nice for e.g. aggregate:

> df = data.frame(l=sample(1:3,10,rep=TRUE), t=letters[1:10]) > aggregate(df$t,df["l"],curry(paste(collapse="")) %c% toupper)   l    x 1 1  ADG 2 2  BCH 3 3 EFIJ 

Which I find much more elegant and editable than:

> aggregate(df$t, df["l"], function(x)paste(collapse="",toupper(x)))   l    x 1 1  ADG 2 2  BCH 3 3 EFIJ 

Basically I want to know - has this already been done for R?

like image 688
Alex Brown Avatar asked Feb 09 '10 11:02

Alex Brown


People also ask

What are curry functions?

A curried function is a function of several arguments rewritten such that it accepts the first argument and returns a function that accepts the second argument and so on. This allows functions of several arguments to have some of their initial arguments partially applied.

What is a functional in R?

Functional programming languages In R, this means that you can do many of the things with a function that you can do with a vector: you can assign them to variables, store them in lists, pass them as arguments to other functions, create them inside functions, and even return them as the result of a function.


1 Answers

Both of these functions actually exist in the roxygen package (see the source code here) from Peter Danenberg (was originally based on Byron Ellis's solution on R-Help):

Curry <- function(FUN,...) {   .orig = list(...);   function(...) do.call(FUN,c(.orig,list(...))) }  Compose <- function(...) {   fs <- list(...)   function(...) Reduce(function(x, f) f(x),                        fs,                        ...) } 

Note the usage of the Reduce function, which can be very helpful when trying to do functional programming in R. See ?Reduce for more details (which also covers other functions such as Map and Filter).

And your example of Curry (slightly different in this usage):

> library(roxygen) > p <- Curry(paste, collapse="") > p(letters[1:10]) [1] "abcdefghij" 

Here's an example to show the utility of Compose (applying three different functions to letters):

> Compose(function(x) x[length(x):1], Curry(paste, collapse=""), toupper)(letters) [1] "ZYXWVUTSRQPONMLKJIHGFEDCBA" 

And your final example would work like this:

> aggregate(df[,"t"], df["l"], Compose(Curry(paste, collapse=""), toupper))   l    x 1 1  ABG 2 2 DEFH 3 3  CIJ 

Lastly, here's a way to do the same thing with plyr (could also easily be done with by or aggregate as already shown):

> library(plyr) > ddply(df, .(l), function(df) paste(toupper(df[,"t"]), collapse=""))   l   V1 1 1  ABG 2 2 DEFH 3 3  CIJ 
like image 116
Shane Avatar answered Sep 23 '22 17:09

Shane