Code:
args <- function() {
list(
x = "How old",
y = "is",
z = "the car?")
}
fun1 <- function(x = "How old", y = "is", z = "the car") {
# collect arguments
args_used <- as.list(match.call()[-1])
# Call fun2() using the args supplied by the user
do.call(fun2, args_used)
}
fun2 <- function(x = args()$x, y = args()$y, z = args()$z) {
paste(x, y, z)
}
Problem
Using fun1()
and/or fun2()
works if used directely, try e.g.,
> fun1("Where", "are", z = "the cars")
[1] "Where are the cars"
However, if I do:
list1 <- list(l1 = "Where", l2 = "Is this")
list2 <- list(l1 = "is", l2 = "the")
list3 <- list(l1 = "Peter", l2 = "new iPhone?")
mapply(function(i, j, k) fun1(x = i, y = j, z = k),
i = list1,
j = list2,
k = list3,
SIMPLIFY = FALSE)
I get
Error in paste(x, y, z) : object 'i' not found
I know why the problem happens and I even know how to fix it using eval(parse(text = ""))
(although I am aware of potential problems of the eval-parse strategy (see, e.g.: this discussion)
Therefore rewriting fun1()
like this:
fun1 <- function(x = "How old", y = "is", z = "the car") {
# collect arguments
args_used <- as.list(match.call()[-1])
args_used <- lapply(names(args_used), function(w) eval(parse(text = w)))
# Call fun2() using the args supplied by the user
do.call(fun2, args_used)
}
and subsequently using mapply(....)
as above works.
However here it becomes tricky.
- Notice what happens if I change
w
inlapply(names(args_used), function(w) eval(parse(text = w)))
tox
(the same holds true fory
andz
. Now callingmapply
as above again, give:$`l1` [1] "x is Peter" $l2 [1] "x the new iPhone?"
Clearly not what I wanted. Again I understand why this happens and a fix would be to not use
x
but something likew
but any name a pick is from now on reserved. Not ideal. The approach also breaks if one of the arguments is called via the
...
argument. Modifyingfun1()
like this:fun1 <- function(x = "How old", y = "is", ...) { # collect arguments args_used <- as.list(match.call()[-1]) args_used <- lapply(names(args_used), function(x) eval(parse(text = x))) # Call fun2() using the args supplied by the user do.call(fun2, args_used) }
now results in
Error in eval(parse(text = x)) : object 'z' not found
Again, I understand why (because the name "z"
is unknown within the fun1()
environement) but the question now is:
How do I solve this issue in a way that it avoids problem 1 and problem 2?