From ?match.call
:
match.call
is most commonly used in two circumstances: […] To pass most of the call to another function […]
After reading that, I expected I could use match.call
when I want to pass all arguments of one function to another function without listing these arguments one by one.
Example: outer1
passes arguments one by one, outer2
uses match.call
.
outer1 <- function(a, b, c) {
inner1(a, b, c)
}
inner1 <- function(a, b, c) {
return(a + b + c$first + c$second)
}
outer2 <- function(a, b, c) {
mycall <- match.call()
inner2(mycall)
}
inner2 <- function(call) {
return(call$a + call$b + call$c$first + call$c$second)
}
outer1(1, 2, list(first = 3, second = 4)) # OK: 10
outer2(1, 2, list(first = 3, second = 4)) # OK: 10
The first problem arises, when -1
instead of 1
is passed to outer2
:
outer2(-1, 2, list(first = 3, second = 4)) # Error in call$a + call$b : non-numeric argument to binary operator
Question 1 : What is the technical difference between passing -1
instead of 1
? I know that
typeof(quote(1)) # double
typeof(quote(-1)) # language
but I suppose that the fact that I passed a language
object in the second case is not the (only) relevant difference because passing something of type language to argument c
works ( typeof(quote(list(first = 3, second = 4))) # language
).
In order to overcome the problem above, I try to eval
all arguments that are of type language
:
outer3 <- function(a, b, c) {
parsedCall <- lapply(match.call()[-1L], FUN=function(argument) {
if(is.language(argument)) {
return(eval(argument))
} else {
return(argument)
}
})
inner3(parsedCall)
}
inner3 <- function(parsedCall) {
return(parsedCall$a + parsedCall$b + parsedCall$c$first + parsedCall$c$second)
}
outer3(-1, 2, list(first = 3, second = 4)) # OK: 8
Question 2: The approach in outer3
seems to "work" but are there further pitfalls I need to take into account? (I know that in some cases it might be disadvantageous to evaluate the arguments but for my case this should not be an issue.)
Question 3: I suppose that the desire to pass all arguments to another function is not very uncommon. Is there a better/standard approach than what I did?
Question 4: Is it advantageous to pass the raw call
to the inner function an do the eval
stuff there? Would this be helpful if I would like to have the arguments as local variables in the inner
functions (instead of elements of the parsedCall
list)? Then, the body of inner3
could be identical to the body of inner1
(while with the current solution, I have to replace a+b
with parsedCall$a + parsedCall$b
).
Regarding your question:
I suppose that the desire to pass all arguments to another function is not very uncommon. Is there a better/standard approach than what I did?
Then I would say this is a more common way to pass the arguments on:
inner1 <- function(a, b, c) {
return(a + b + c$first + c$second)
}
outer3 <- function(a, b, c) {
mycall <- match.call()
mycall[[1]] <- as.symbol("inner1") # use inner 1
eval(mycall)
}
outer4 <- function(a, b, c) {
.args <- as.list(match.call()[-1])
do.call(inner1, .args)
}
outer3(-1, 2, list(first = 3, second = 4))
#R> [1] 8
outer4(-1, 2, list(first = 3, second = 4))
#R> [1] 8
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.