How to concatenate/compose functions in R?

More on Curry'ing and Composing

There is partial in package pryr which achieves roughly the same as Curry in package functional but in a different way.

(Curry creates a list of arguments and feeds it to do.call. partial literally creates a new function which calls the first function with default arguments set.)

In this discussion in R-devel, Luke Tierney points out some problems with Curry ("This has quite different behavior with respect to evaluation/lazy evaluation than an analogous anonymous function. In addition, do.call has some fairly strange aspect so it with respect to how it interacts with sys.xyz functions, and does not do what you want in many cases I care about when quote = FALSE, as is the default. Adding this would create more problems than is solves."). These issues (however infrequently they might arise) are not a concern with partial.

Other approaches to currying / partial function application:

wargs in package dostats (similar to partial but has something distinctive:

wargs(mean, na.rm=TRUE)(c(1:5, NA), na.rm=FALSE)
# this works and gives NA as answer, so na.rm=FALSE overrides na.rm=TRUE
# with partial, this would result in an error:
#### formal argument "na.rm" matched by multiple actual arguments

There is %but% in package operators but it doesn't work with generic functions. So ...

df <- data.frame(a=c(1:5,NA), b=c(NA, 2:6))
sapply(df, mean %but% list(na.rm=TRUE))
#  a  b 
# NA NA 
# ... but2
sapply(df, sd %but% list(na.rm=TRUE))
#        a        b 
# 1.581139 1.581139 

And it has a separate mechanism for setting logical arguments:

# from the help page
grep %but% "pf"     # grep, with perl and fixed set to TRUE

As for compose, there are identically named (but different) versions in both pryr and dostats: compose and %.% -- and both are different from functional:::Compose.

Finally, I would add that pryr includes f which one can conveniently use instead of function in anonymous functions.


Using magrittr

If we require(magrittr), then we can

sapply(x, . %>% unique %>% sum)

or even

x %>% sapply(. %>% unique %>% sum)

or evener

x %>% sapply(unique) %>% sapply(sum)

To quote from the documentation:

  • x %>% f is equivalent to f(x)
  • x %>% f(y) is equivalent to f(x, y)
  • x %>% f %>% g %>% h is equivalent to h(g(f(x)))

For this you can use the Compose function in the functional package, which is available on CRAN.:

library(functional)
sapply(x, Compose(unique,sum))