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
winlapply(names(args_used), function(w) eval(parse(text = w)))tox(the same holds true foryandz. Now callingmapplyas 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
xbut something likewbut 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?