简体   繁体   中英

match.call with function call supplied

I'd like to capture all arguments and values and return a named list. I'm having trouble with a situation where the value supplied is a function call.

The following produces an object of class "call", which is inconvenient to me, because I want to call paste on it:

fun1 = function(a = 1) as.list(match.call()[-1])
value1 = fun1(a = letters[1:2])
class(value1[[1]])
[1] "call"
paste(value1[[1]], collapse = " - ")
[1] "[ - letters - 1:2" #not useful to me

As a workaround, I can call eval to get the character vector created by c (the lapply function is there to illustrate that when having multiple arguments, eval would be called on all of them):

fun2 = function(a = 1) lapply(as.list(match.call()[-1]), eval)
value2 = fun2(a = letters[1:2])
class(value2[[1]])
[1] "character"
paste(value2[[1]], collapse = " - ")
[1] "a - b" #that's what I want

Is there a better way to do this? Calling eval on a bunch of things just to get the values seems a bit weird to me.

EDIT: The idea behind this is that I would like to pass a list of arguments to a function (which accepts a named list for one of it's arguments) within the original function. I'd like to capture values provided by the user, and default ones (for arguments where the user did not provide anything).

I learned elsewhere that I can get all of that by a combination of match.call and formals . But then, say I need to pass that to the query argument of the httr::GET function, and do some processing on it before I do so (such as adding " - " between "a" and "b"). I then end up with something like "[ - letters - 1:2" instead of "a - b".

I sense that if the answer is using eval , then I am probably asking the wrong question.

I sense that you are looking for something more general, so not sure if this is entirely what you are looking for but its simpler and gives you the desired result. The critical piece here is do.call()

fun1 = function(a = 1) {
  L1 <- as.list(match.call())
  do.call(paste0, list(L1$a, sep="", collapse=" - "))
}

value1 = fun1(a = letters[1:2])

Well, I think you need to decide which part of your code needs evaluation and what needs not.
It's not entirely clear from your example how general you want to go, but your example-question can be solved by a simple list(), you only need a custom function for providing defaults:

myfun <- function(a=1) list(a=a)
value <- myfun(a=letters[1:2]))
paste(value[[1]], collapse = " - ")
# Basically: value <- list(a=letters[1:2])), or paste(letters[1:2], collapse= " - ")

Generally, you use match.call() without any arguments to find out in what way your function was called. Sometimes it's useful to know whether fun(a=c('a', 'b')) was called, or fun1(a = letters[1:2]), so match.call tells you this, without evaluating anything.

So if you want to actually do something with your arguments, just call them directly, and you can later pass them on to another function

mypaste <- function(..., sep=' -CustomSep- ', collapse=' -Mycollapse- ', prefix='Value:') {
  if(length(list(...))>0) {
    paste(prefix, ..., sep=sep, collapse=collapse)
  } else {
    text <- character(0)
  }
}

This function is just a variation on paste, but you can make it extensive as you want.

And I get the impression that you want a general case where you match your arguments to the arguments of another function, but to answer that question I'd need to know more about what exactly you are trying to accomplish.

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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM