Home > OS >  Is there a way to use do.call without explicitly providing arguments
Is there a way to use do.call without explicitly providing arguments

Time:09-18

Part of a custom function I am trying to create allows the user to provide a function as a parameter. For example

#Custom function
result <- function(.func){
  do.call(.func, list(x,y))
}

#Data
x <- 1:2
y <- 0:1

#Call function
result(.func = function(x,y){ sum(x, y) })

However, the code above assumes that the user is providing a function with arguments x and y. Is there a way to use do.call (or something similar) so that the user can provide a function with different arguments? I think that the correct solution might be along the lines of:

#Custom function
result <- function(.func){
  do.call(.func, formals(.func))
}

#Data
m <- 1:3
n <- 0:2
x <- 1:2
y <- 0:1
z <- c(4,6)

#Call function
result(.func = function(m,n){ sum(m, n) })
result(.func = function(x,y,z){ sum(x,y,z) })

But this is not it.

CodePudding user response:

This works.

#Custom function
result <- function(.func){
  do.call(.func, lapply(formalArgs(.func), as.name))
}

#Data
m <- 1:3
n <- 0:2
x <- 1:2
y <- 0:1
z <- c(4,6)

#Call function
result(.func = function(m,n){ sum(m, n) })
result(.func = function(x,y,z){ sum(x,y,z) })

CodePudding user response:

This seems like a bit of a pointless function, since the examples in your question imply that what you are trying to do is evaluate the body of the passed function using variables in the calling environment. You can certainly do this easily enough:

result <- function(.func){
  eval(body(.func), envir = parent.frame())
}

This gives the expected results from your examples:

x <- 1:2
y <- 0:1

result(.func = function(x,y){ sum(x, y) })
#> [1] 4

and

m <- 1:3
n <- 0:2
x <- 1:2
y <- 0:1
z <- c(4,6)

result(.func = function(m,n){ sum(m, n) })
#> [1] 9
result(.func = function(x,y,z){ sum(x,y,z) })
#> [1] 14

But note that, when the user types:

result(.func = function(x,y){ ...user code... })

They get the same result they would already get if they didn't use your function and simply typed

...user code....

You could argue that it would be helpful with a pre-existing function like mean.default:

x <- 1:10
na.rm <- TRUE
trim <- 0
result(mean.default)
#> [1] 5.5

But this means users have to name their variables as the parameters being passed to the function, and this is just a less convenient way of calling the function.

It might be useful if you could demonstrate a use case where what you are proposing doesn't make the user's code longer or more complex.

  •  Tags:  
  • r
  • Related