Is it possible to chain functions in R?
Sample data:
m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)
For example, I would like to r
I would use the magrittr
package. It has a "pipe" operator that takes the result of one function and passes it in as an argument to the next:
m <- matrix(c(1:10, 11:20), nrow = 10, ncol = 2)
m %>% mean %>% sum
Ceci n'est pas un pipe!
Try the functional package:
library(functional)
squared <- function(x)x*x
Compose(sum, squared)(m)
## [1] 44100
squared(sum(m))
## [1] 44100
EDIT:
Regarding the question in the comments of another response about arguments here is an example of composing with arguments. Curry
is also from the functional package:
addn <- function(n, x) x + n
Compose(Curry(addn, 1), squared)(10)
## [1] 121
squared(addn(1, 10))
## [1] 121
EDIT 2:
Regarding question about debugging, debug
works if the function is curried. If its not already curried then wrap it in Curry
:
# this works since addn is curried
debug(addn)
Compose(Curry(addn, 1), squared)(10)
# to debug squared put it in a Curry -- so this works:
debug(squared)
Compose(Curry(addn, 1), Curry(squared))(10)
In a similar vein to Ben's answer, but allowing arguments:
`%@%` <- function(x, f) eval.parent(as.call(append(as.list(substitute(f)), list(x), 1)))
x %@% mean %@% sqr # => 6.25
c(1, 2, NA, 3, 4) %@% mean(na.rm=T) %@% sqr # => 6.25
m %@% colMeans() %@% sum() # => 21
Sort of, but I think it's un-idiomatic and maybe fragile/not a good idea. (This is implied, I think, by @RichieCotton's comment above.)
From http://cran.r-project.org/doc/manuals/R-lang.html :
10.3.4 Special operators
R allows user-defined infix operators. These have the form of a string of characters delimited by the ‘%’ character. The string can contain any printable character except ‘%’. The escape sequences for strings do not apply here.
Note that the following operators are predefined
%% %*% %/% %in% %o% %x%
"%@%" <- function(x,f) {
f(x)
}
sqr <- function(x) x^2
x <- 1:4
x %@% mean ## 2.5
x %@% mean %@% sqr ## 6.25
x %@% (mean %@% sqr) ## fails
Given m
as defined above -- maybe what you had in mind?
m %@% colMeans %@% sum ## 21
Notes:
mean(x)
always returns a scalar (i.e. a length-1 vector), so sum(mean(x))
is always going to be the same as mean(x)
%
, so you can't have anything as compact as a single symbol (and %%
is taken already).edit: the question now asks how additional arguments can be incorporated. I don't think the syntax suggested (x %@% fun1(arg1) %@% fun2(arg2)
) will work without some serious magic. This is the closest I can get at the moment -- creating a wrapper function that creates a modified version of the original function.
F <- function(f,...) {
function(x) {
f(x,...)
}
}
Testing:
pow <- function(x,b=2) { x^b }
sqr <- function(x) x^2
x <- 1:4
x %@% F(mean,na.rm=TRUE) ## 2.5
x %@% F(mean,na.rm=TRUE) %@% F(pow,3) ## 16.25
(Note that I have used F
as a function here, which may be dicey in some situations because it overwrites the F==FALSE
shortcut)