Using the following function foo()
as a simple example, I'd like to distribute the values given in ...
two different functions, if possible.
foo <- function(x, y, ...) { list(sum = sum(x, ...), grep = grep("abc", y, ...)) }
In the following example, I would like na.rm
to be passed to sum()
, and value
to be passed to grep()
. But I get an error for an unused argument in grep()
.
X <- c(1:5, NA, 6:10) Y <- "xyzabcxyz" foo(X, Y, na.rm = TRUE, value = TRUE) # Error in grep("abc", y, ...) : unused argument (na.rm = TRUE)
It seems like the arguments were sent to grep()
first. Is that correct? I would think R would see and evaluate sum()
first, and return an error for that case.
Furthermore, when trying to split up the arguments in ...
, I ran into trouble. sum()
's formal arguments are NULL
because it is a .Primitive
, and therefore I cannot use
names(formals(sum)) %in% names(list(...))
I also don't want to assume that the leftover arguments from
names(formals(grep)) %in% names(list(...))
are to automatically be passed to sum()
.
How can I safely and efficiently distribute ...
arguments to multiple functions so that no unnecessary evaluations are made?
In the long-run, I'd like to be able to apply this to functions with a long list of ...
arguments, similar to those of download.file()
and scan()
.
A function's syntax refers to the layout of the function and includes the function's name, parenthesis, comma separators, and its arguments. The arguments are always surrounded by parentheses and individual arguments are separated by commas.
The split() function takes two parameters as an argument, i.e., separator and maxsplit. Both parameters are optional. The separator splits the string. If you do not specify any separator, then the split() function will split the string on the basis of white space.
Answer 1: When it comes to passing arguments to function, the maximum number of arguments that is possible to pass is 253 for a single function of the C++ programming language. Furthermore, the separation of arguments takes place by commas.
Yes, it matters. The arguments must be given in the order the function expects them.
Separate Lists If you really want to pass different sets of parameters to different functions then it's probably cleaner to specify separate lists:
foo <- function(x, y, sum = list(), grep = list()) { list(sum = do.call("sum", c(x, sum)), grep = do.call("grep", c("abc", y, grep))) } # test X <- c(1:5, NA, 6:10) Y <- "xyzabcxyz" foo(X, Y, sum = list(na.rm = TRUE), grep = list(value = TRUE)) ## $sum ## [1] 55 ## ## $grep ## [1] "xyzabcxyz"
Hybrid list / ... An alternative is that we could use ... for one of these and then specify the other as a list, particularly in the case that one of them is frequently used and the other is infrequently used. The frequently used one would be passed via ... and the infrequently used via a list. e.g.
foo <- function(x, y, sum = list(), ...) { list(sum = do.call("sum", c(x, sum)), grep = grep("abc", y, ...)) } foo(X, Y, sum = list(na.rm = TRUE), value = TRUE)
Here are a couple of examples of the hybrid approach from R itself:
i) The mapply
function takes that approach using both ...
and a MoreArgs
list:
> args(mapply) function (FUN, ..., MoreArgs = NULL, SIMPLIFY = TRUE, USE.NAMES = TRUE) NULL
ii) nls
also takes this approach using both ...
and the control
list:
> args(nls) function (formula, data = parent.frame(), start, control = nls.control(), algorithm = c("default", "plinear", "port"), trace = FALSE, subset, weights, na.action, model = FALSE, lower = -Inf, upper = Inf, ...) NULL
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With