1

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)
}

1 Answer 1

3

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.

Sign up to request clarification or add additional context in comments.

2 Comments

Is there any way to link factor directly to f in the final function call? In case I want to expand it to include multiple functions
See my edit for two alternatives.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.