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

 ̄綄美尐妖づ 提交于 2019-11-28 03:06:33

The standard place for functional programming in R is now the functional library.

From the library:

functional: Curry, Compose, and other higher-order functions

Example:

   library(functional)
   newfunc <- Curry(oldfunc,x=5)

CRAN: https://cran.r-project.org/web/packages/functional/index.html

PS: This library substitutes the ROxigen library.

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

There is a function called Curry in the roxygen package.
Found via this conversation on the R Mail Archive.

Aaron McDaid

A more complex approach is required if you want the 'names' of the variables to pass through accurately.

For example, if you do plot(rnorm(1000),rnorm(1000)) then you will get nice labels on your x- and y- axes. Another example of this is data.frame

> data.frame( rnorm(5), rnorm(5), first=rpois(5,1), second=rbinom(5,1,0.5) )
    rnorm.5. rnorm.5..1 first second
1  0.1964190 -0.2949770     0      0
2  0.4750665  0.8849750     1      0
3 -0.7829424  0.4174636     2      0
4  1.6551403  1.3547863     0      1
5  1.4044107 -0.4216046     0      0

Not that the data.frame has assigned useful names to the columns.

Some implementations of Curry may not do this properly, leading to unreadable column names and plot labels. Instead, I now use something like this:

Curry <- function(FUN, ...) {
    .orig = match.call()
    .orig[[1]] <- NULL # Remove first item, which matches Curry
    .orig[[1]] <- NULL # Remove another item, which matches FUN
    function(...) {
        .inner = match.call()
        .inner[[1]] <- NULL # Remove first item, which matches Curry
        do.call(FUN, c(.orig, .inner), envir=parent.frame())
    }
}

This is quite complex, but I think it's correct. match.call will catch all args, fully remembering what expressions defined the args (this is necessary for nice labels). The problem is that it catches too many args -- not just the ... but also the FUN. It also remembers the name of the function that's being called (Curry).

Therefore, we want to delete these first two entries in .orig so that .orig really just corresponds to the ... arguments. That's why we do .orig[[1]]<-NULL twice - each time deletes an entry and shifts everything else to the left.

This completes the definition and we can now do the following to get exactly the same as above

Curry(data.frame, rnorm(5), rnorm(5) )( first=rpois(5,1) , second=rbinom(5,1,0.5) )

A final note on envir=parent.frame(). I used this to ensure that there won't be a problem if you have external variables called '.inner' or '.orig'. Now, all variables are evaluated in the place where the curry is called.

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!