Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

match.call() returns a function or a symbol, but symbols can't be used by do.call()

Tags:

r

I want to do a recursive function call with modified arguments in R.

recursive_function_call <- function(call) {

    fun_call <- as.list(call) 
    fun <- fun_call[[1]]
    arguments <- fun_call[-1]

    ## Modify Arguments 
    arguments$drop_option <- NULL

    ## Call Function
    result <- do.call(what = fun, args = arguments)
    return(result)
}
recursive_function_call(match.call())

I want to call this function from an array of similar functions. If this gets called from a top-level function the variable fun will be of type symbol, while it gets on a lower level function call fun will be a function.

My problem is that do.call() fails when the function is a symbol, while for the arguments it's OK to be symbols.

My solution is to convert the symbol to a string.

if (is.symbol(fun_call[[1]])) fun <- as.character(fun_call[[1]]) else fun <- fun_call[[1]]
  1. Is there a better way to get the function of a call object?
  2. Is there a way to check the symbol will be available after I converted it into a string? Or can I avoid the conversion?
like image 489
ndevln Avatar asked Nov 15 '19 13:11

ndevln


People also ask

What does match call do in R?

match. call returns a call in which all of the specified arguments are specified by their full names.

Which character is used for calling a function?

The first element of the list becomes the function part of the call, so should be a function or the name of one (as a symbol; a character string will not do). If you think of using as. call(<string>) , consider using str2lang(*) which is an efficient version of parse(text=*) . Note that call() and as.


1 Answers

As you’ve noticed, do.call constructs and invokes a call expression (and invokes it) from a function name (or function) and a list of arguments. But you already have a call expression, no need for do.call — so you can directly invoke it using eval or eval.parent:

recursive_function_call = function(call) {
    call$drop_options = NULL
    eval.parent(call)
}

recursive_function_call(match.call())

That said, I’m not sure what your function’s purpose is. Are you looking for Recall?

Alternatively, you can use as.call to coerce a list into a function call expression. And, once again, eval then evaluates it:

eval.parent(as.call(fun_cal))

— in fact, as.call is essentially the inverse of as.list on a call expression: identical(as.call(as.list(call)), call) is TRUE.

like image 74
Konrad Rudolph Avatar answered Oct 12 '22 01:10

Konrad Rudolph