Use match.call to pass all arguments to other function

非 Y 不嫁゛ 提交于 2019-12-07 04:18:52

问题


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).


回答1:


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]) # use inner 1
+   do.call(inner1, .args)
+ }
> 
> outer3(-1, 2, list(first = 3, second = 4))
[1] 8
> outer4(-1, 2, list(first = 3, second = 4))
[1] 8


来源:https://stackoverflow.com/questions/29327423/use-match-call-to-pass-all-arguments-to-other-function

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!