I have two functions nested in another function and I would like that the arguments declared in parent were passed to the child (only when the argument is relevant to the function).
# child function 1
child_f1 <- function(x1 = 1, x2 = 3) {
res <- x1^2 4 * x2
}
# child function 2
child_f2 <- function(z = 2) {
res <- z * 1.345
}
# parent function
parent_f <- function(y = 4, ...) {
res <- (child_f1(...) ^ y) child_f2(...)
# print(res)
return(res)
}
Test below:
parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
# Error in child_f1(...) (from #2) : unused argument (z = 3)
# Expected result:
(((2)^2 4*(0)) ^ (2)) (3) * 1.345
[1] 20.04
How do I tell child_f1
that has to use only x1
and x2
(if available, otherwise use default value) and child_f2
that has to use only z
(if available, otherwise use default value)?
I would like to stick with the usage of ...
rather than re-write a parent_f()
with all the possible parameters declared.
CodePudding user response:
Add ... to each child to slurp up the unused arguments. parent_f is unchanged.
child_f1 <- function(x1 = 1, x2 = 3, ...) {
res <- x1^2 4 * x2
}
child_f2 <- function(z = 2, ...) {
res <- z * 1.345
}
parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
## [1] 20.035
If you can't modify the children or the parent then use this:
child_f1_orig <- child_f1
child_f1 <- function(x1 = 1, x2 = 3, ...) child_f1_orig(x1 = x1, x2 = x2)
child_f2_orig <- child_f2
child_f2 <- function(z = 2, ...) child_f2_orig(z = z)
parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
## [1] 20.035
CodePudding user response:
We can use formals
to reduce the arguments to those supported by the child function. This relies on all arguments being named, which is supported here. After that, we use do.call
to programmatically call a function with a list of arguments.
# parent function
parent_f <- function(y = 4, ...) {
dots <- list(...)
dots1 <- dots[intersect(names(dots), names(formals(child_f1)))]
dots2 <- dots[intersect(names(dots), names(formals(child_f2)))]
res <- (do.call(child_f1, dots1) ^ y) do.call(child_f2, dots2)
# print(res)
return(res)
}
parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
# [1] 20.035
CodePudding user response:
You can make use of formal
and design a proper function for your usecase
use_fun_with_args <- function(fun, ...) {
dots <- list(...)
do.call(fun, args = dots[intersect(names(formals(fun)),
names(dots))])
}
# parent function
parent_f <- function(y = 4, ...) {
res <- (use_fun_with_args(fun = child_f1, ...) ^ y) use_fun_with_args(fun = child_f2, ...)
# print(res)
return(res)
}
parent_f(y = 2, x1 = 2, x2 = 0, z = 3)
#> [1] 20.035