Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

base R substitute names of the arguments to function call

The ultimate goal in the question is to construct the following unevaluated call using r's computing on the language, where list, a_name and 50L are provided from parameters.

list(a_name = 50L)

Which internally looks like

str(quote(list(a_name = 50L)))
# language list(a_name = 50L)

str(as.list(quote(list(a_name = 50L))))
#List of 2
# $       : symbol list
# $ a_name: int 50

I will put my variables in a list so the further code will be cleaner.

params = list(my_fun = as.name("list"), my_name = "a_name", my_value = 50L)

# What I tried so far?

# 1. The first thing that one would try

substitute(my_fun(my_name = my_value),
           params)
#list(my_name = 50L) ## `my_name` was not substituted!

# 2. Workaround get the same output, but only after `setNames` call evaluation, so doesn't really answer the question about constructing specific call

substitute(setNames(my_fun(my_value), my_name), ## alternatively could be `structure(..., names=my_name)`
           params)
#setNames(list(50L), "a_name")

# 3. Another workaround, not really computing on the language but parsing, and integer L suffix is gone!

with(expr = parse(text=paste0(my_fun, "(", my_name, " = ", my_value, ")"))[[1L]],
     data = params)
#list(a_name = 50)

# 4. Working example using rlang

with(expr = rlang::call2(my_fun, !!my_name := my_value),
     data = params)
#list(a_name = 50L)

Is there any way in base r to construct required call? Basically to get exactly same output as rlang way but using base r.

Note that this Question is not a duplicate of this which was strictly asking for rlang solution. This Question asks for a way to achieve it using base r. If there is no way to achieve it, I would like to know that as well. Thank you.

like image 217
jangorecki Avatar asked Mar 08 '20 12:03

jangorecki


People also ask

Can you call a function in a function R?

Nested Function Calls in R Now consider the arguments: these can be of any type and can have default values inside the function. The latter provides an output even when explicit values are not passed to it. Finally, you can call another function within a function.

What type of arguments can a function take in R?

Arguments are the parameters provided to a function to perform operations in a programming language. In R programming, we can use as many arguments as we want and are separated by a comma. There is no limit on the number of arguments in a function in R.

When using a function the functions arguments can be specified by?

Because all function arguments have names, they can be specified using their name. Specifying an argument by its name is sometimes useful if a function has many arguments and it may not always be clear which argument is being specified. Here, our function only has one argument so there's no confusion.

How do you name arguments in R?

Arguments in R Programming Language Arguments are always named when you define a function. When you call a function, you do not have to specify the name of the argument. Arguments are optional; you do not have to specify a value for them.

What is the use of do call in R?

The do.call The do.call R function executes a function by its name and a list of corresponding arguments. The call The call R function creates objects of the class “call”.

What is a substitute call in R?

a call, i.e., an R object of class (and mode) "call". an environment or a list object. Defaults to the current evaluation environment. The typical use of substitute is to create informative labels for data sets and plots. The myplot example below shows a simple use of this facility.

What is the difference between arguments and functions in R?

You will also learn to add a mult argument and default value in R and usage of dots argument, function as an argument and anonymous functions in R. Arguments are always named when you define a function. When you call a function, you do not have to specify the name of the argument. Arguments are optional; you do not have to specify a value for them.


1 Answers

Assuming that the question is how to produce a call object whose function is the first argument of params, whose single argument name is the value of the second component of params and whose argument value is the third component of params then c2 is that call object. We verify that the cakl object produced is identical to the rlang call object shown in the question.

c2 <- as.call(setNames(params, c("", "", params2$my_name))[-2])

# verify that c2 equals the output of the rlang example in question
c1 <- with(expr = rlang::call2(my_fun, !!my_name := my_value), data = params)

identical(c1, c2)
## [1] TRUE

This generalizes so that if the call has more arguments so that params has length n+2 and the second component of params is a vector of names whose length is n then it still works.

If you have control over the input I think it would make more sense to define the input list as having one component for the function name and one component for each argument with the names of the components being the argument names (as opposed to a separate argument to hold the names). In that case we could simply write the following. Actually what the above does is to transform params into that form and then use as.call so we might as well provide that form from the start if possible.

as.call(params2)  # params2[[1]] is func name, params2[-1] is named args

Note

To execute the call just use:

eval(c2)

or we could use do.call:

do.call(as.character(params[[1]]), setNames(tail(params, -2), params[[2]]))
like image 143
G. Grothendieck Avatar answered Nov 15 '22 00:11

G. Grothendieck