Reputation: 7517
I was wondering if there is an Base R function to extract the argument values that are in use in a particular function call?
For example, for each of the objects x
, y
and z
below, is there a generic way to extract the arguments names (e.g., n
, sd
, rate
, scale
) in use and the values (e.g., 1e4
for n
) assigned by the user or the system to each of those arguments?
NOTE: in certain "R" functions such extraction is easily done. For example, in density()
, one can easily extract the argument values
using density()$call
.
x = rnorm(n = 1e4, mean = 2, sd = 4)
y = rlogis(1e4, 20)
z = rexp(1e4, 5)
Upvotes: 2
Views: 720
Reputation: 43334
This is really not an easy thing to do. If you're building the function, you can capture the call with match.call
, which can be parsed without too much trouble:
f <- function(x, y = 1, ...){
cl <- match.call()
as.list(cl[-1])
}
str(f(1))
#> List of 1
#> $ x: num 1
str(f(1, 'foo'))
#> List of 2
#> $ x: num 1
#> $ y: chr "foo"
str(f(1, 'foo', list(3), fun = sum))
#> List of 4
#> $ x : num 1
#> $ y : chr "foo"
#> $ : language list(3)
#> $ fun: symbol sum
Note match.call
only captures the call, and doesn't add in default parameters (there's no y
in the first example). Those can be accessed with formals(f)
, since f
isn't primitive, so complete arguments could be created via
user_args <- f(1)
fun_args <- formals(f)
fun_args[names(user_args)] <- user_args
str(fun_args)
#> List of 3
#> $ x : num 1
#> $ y : num 1
#> $ ...: symbol
This approach doesn't work well for completed dots, but if they're completed then match.call
itself should suffice. To extract the parameters passed to an existing function, you could write a wrapper with match.call
, but it's hardly practical to reconstruct every function, and the call you capture will look funny anyway unless you overwrite existing functions. As long as the function isn't primitive, you could use quote
to enable the formals
approach, though:
cl <- quote(rnorm(5, 2))
user_args <- as.list(cl[-1]) # subset call to only args
fun_args <- formals(as.character(cl[1])) # subset call to only function
names(user_args) <- names(fun_args)[seq(length(user_args))]
fun_args[names(user_args)] <- user_args
str(fun_args)
#> List of 3
#> $ n : num 5
#> $ mean: num 2
#> $ sd : num 1
Another approach is to use rlang, whose functions handle primitives well (fn_fmls(sum)
), can extract parts of the call easily and reliably (lang_fn
, lang_args
), name unnamed parameters accurately (lang_standardize
), and more. Together with purrr's new list_modify
(dev version), it all becomes fairly painless:
library(rlang)
fun_call <- quo(rnorm(5))
fun_call
#> <quosure: frame>
#> ~rnorm(5)
default_args <- fn_fmls(lang_fn(fun_call))
str(default_args)
#> Dotted pair list of 3
#> $ n : symbol
#> $ mean: num 0
#> $ sd : num 1
user_args <- lang_args(lang_standardise(fun_call))
str(user_args)
#> List of 1
#> $ n: num 5
calling_args <- purrr::list_modify(default_args, user_args)
str(calling_args)
#> Dotted pair list of 3
#> $ n : num 5
#> $ mean: num 0
#> $ sd : num 1
Upvotes: 4