Suppose I have a function in R that takes multiple arguments, and I'd like to reduce it to a function of fewer arguments by setting some of the arguments to pre-specified values. I'm trying to figure out what is the best way to do this is in R.
For example, suppose I have a function
f <- function(a,b,c,d){a+b+c+d}
I'd like to create or find a function partial that would do the following
partial <- function(f, ...){
#fill in code here
}
new_f <- partial(f, a=1, c= 2)
new_f
would be a function of b
and d
and would return 1+b+2+d
In python I would do
from functools import partial
def f(a,b,c,d):
return a+b+c+d
new_f = partial(f, a=1, c= 2)
I'm actually doing this repeatedly and so I need for this to be as efficient as possible. Can anyone point me to the most efficient way to do this? Right now the best I can do is
partial <- function(f, ...){
z <- list(...)
formals(f) [names(z)] <- z
f
}
Can anyone let me know of a faster way or the best way to do this? This is simply too slow.
There are functions in the pryr
package that can handle this, namely partial()
f <- function(a, b, c, d) a + b + c + d
pryr::partial(f, a = 1, c = 2)
# function (...)
# f(a = 1, c = 2, ...)
So you can use it like this -
new_fun <- pryr::partial(f, a = 1, c = 2)
new_fun(b = 2, d = 5)
# [1] 10
## or if you are daring ...
new_fun(2, 5)
# [1] 10
You could also simply change f()
's formal arguments with
f <- function(a, b, c, d) a + b + c + d
formals(f)[c("a", "c")] <- list(1, 2)
f
# function (a = 1, b, c = 2, d)
# a + b + c + d
f(b = 2, d = 5)
# [1] 10
But with the latter, you must name the b
and d
arguments in f()
to avoid an error when you want to leave a
and c
as their default values.
You could roll your own without too much coding using do.call
:
partial <- function(f, ...) {
l <- list(...)
function(...) {
do.call(f, c(l, list(...)))
}
}
Basically partial
returns a function that stores f
as well as the originally provided arguments (stored in list l
). When this function is called, it is passed both the arguments in l
and any additional arguments. Here it is in action:
f <- function(a, b, c, d) a+b+c+d
p <- partial(f, a=2, c=3)
p(b=0, d=1)
# [1] 6
You have also Curry
from package functional
:
library(functional)
f <- function(a, b, c, d) a+b+c+d
ff = Curry(f, a=2, c=10)
ff(1,5)
#[1] 18
ff(b=1,d=5)
#[1] 18