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.
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.
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.
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.
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.
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”.
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.
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.
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
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]]))
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With