Home > Software engineering >  How do I add arguments for a function used as an input to another function in R?
How do I add arguments for a function used as an input to another function in R?

Time:09-05

I have a global function of roughly the form:

demo_fcn <- function(f, x1,x2){
  r = x1 - x2 
  return(f(r))
}

I want to create this function in a general way so that users can add their own f with their own custom inputs, so long as there is an input slot for r. Say we take f to be the following function

f <- function(input, factor){
   out = input^factor
   return(out)
}

In this case, input = r, so that the user is able to call

demo_fcn(f(factor=2),x1=2,x2=3)

I get the error

Error in f(factor = 2) : argument "input" is missing, with no default

The desired outcome here should be the following code running

r = 2-3
f(input=r, factor=2)

The end goal is to implement this in a more complicated function, with multiple arguments for both demo_fcn and f

demo_fcn <- function(f, x1,x2){
  r1 = x1 - x2
  r2 = x1 x2 
  return(f(r1,r2))
}
f <- function(input1, input2, factor1,factor2){
   out = input^factor1   input2^factor2
   return(out)
}

CodePudding user response:

One way is to pass a function (not a function call), and use ... in the top function to pass additional arguments.

demo_fcn <- function(f, x1, x2, ...) {
  r = x1 - x2
  f(r, ...)
}

f <- function(input, factor){
 out = input^factor
 out
}

demo_fcn(f, x1=2, x2=5, factor=2)
# [1] 9

If you want to have multiple such functions, then you can do:


demo_fcn <- function(f1, f2, x1, x2, f1opts = NULL) {
  r = x1 - x2
  do.call(f, c(list(r), f1opts))
}
demo_fcn(f, x1=2, x2=5, f1opts=list(factor=2))

Yet another alternative, taking from curve, which may match more closely what you're hoping for.

demo_fcn <- function(expr, x1, x2, xname = "x") {
  r = x1 - x2
  sexpr <- substitute(expr)
  if (is.name(sexpr)) {
    expr <- call(as.character(sexpr), as.name(xname))
  } else {
    if (!((is.call(sexpr) || is.expression(sexpr)) && xname %in%
            all.vars(sexpr)))
      stop(gettextf("'expr' must be a function, or a call or an expression containing '%s'",
                    xname), domain = NA)
    expr <- sexpr
  }
  ll <- list(x = r)
  names(ll) <- xname
  eval(expr, envir = ll, enclos = parent.frame())
}

demo_fcn(f(x, factor=2), x1=2, x2=5)
# [1] 9

See ?curve for more explanation of xname=, but in short: use x in your call to f(.) though it does not use any object named x in the local or other environment, it is just a placeholder. If you prefer, you can change to xname="input" and demo_fcn(f(input,factor=2),...) for the same effect, but realize that in that call, input is still a placeholder, not a reference to an object.

  • Related