Search code examples
roptparse

How pass unknown set of parameters to R function


I have a function like

myfunc <- function(x, y=x){
  x+y
}

which (obviously) defaults the value of y to x if y is not passed to the function.

Now, I'm using optparse to read some command line arguments to a script which calls myfunc.

# myscript.R

option_list <- list(
  make_option(c("--x"), type="numeric"),
  make_option(c("--y"), type="numeric")
)

print(myfunc(opt$x, opt$y))

The problem with the code above is, it forces the user to provide a value for y (otherwise an error will be thrown). Instead, I'd like to call myfunc using all and only the parameters provided by the user. How can I accomplish this in the most elegant, scalable, generalize-able way?

Note - for those familiar with Python, I think I want do something similar to dictionary unpacking using whatever values are inside opt.


Solution

  • If you have a named list of arguments from optparse that you want to provide to a function, you can do so with do.call:

    # Provide x and y
    opts <- list(x=2, y=3)
    do.call(myfunc, opts)
    # [1] 5
    
    # Provide only x
    opts <- list(x=2)
    do.call(myfunc, opts)
    # [1] 4
    

    As you note, this is basically "dictionary unpacking"/"splatting" from Python. You could then use optparse to grab the values for x and y, making y an optional input on the command line:

    # optparse.R
    library(optparse)
    option_list <- list(make_option("--x", type="integer", default=0),
                        make_option("--y", type="integer"))
    opt <- parse_args(OptionParser(option_list=option_list))
    myfunc <- function(x, y=x) x+y
    do.call(myfunc, opt[names(opt) %in% c("x", "y")])
    # > Rscript optparse.R --x=2 --y=3
    # [1] 5
    # > Rscript optparse.R --x=2
    # [1] 4
    

    By using the R function being called to compute the default value of y instead of the command-line parser, it is simple to make more complicated defaults for y, such as y=min(0, x).

    # optparse.R
    library(optparse)
    option_list <- list(make_option("--x", type="integer", default=0),
                        make_option("--y", type="integer"))
    opt <- parse_args(OptionParser(option_list=option_list))
    myfunc <- function(x, y=min(0, x)) x+y
    do.call(myfunc, opt[names(opt) %in% c("x", "y")])
    # > Rscript optparse.R --x=-2
    # [1] -4
    # > Rscript optparse.R --x=2
    # [1] 2