For a nested function such as
fun_parent <- function(var) {
fun_child <- function(x) {
x var
}
return(fun_child)
}
How can I customize the content of the returned function fun_child based on the input var?
For example,
test <- fun_parent(var = "y")
print(test)
Desirable output:
function(x) {
x y
}
<environment: xxxxxx>
Actual (undesirable) output:
function(x) {
x var
}
<environment: 0x7f7f20126b70>
Any help would be greatly appreciated!
CodePudding user response:
If you need to pull a value from the object list based on a name given as a character, then the get function suffices.
fun_parent <- function(var) {
fun_child <- function(x) {
x get(var)
}
return(fun_child)
}
test <- fun_parent(var = "y")
print(test)
#function(x) {
# x get(var)
# }
#
#<environment: 0x5654f87a1ae8>
Y=6
test(4)
#[1] 10
z=10
test <- fun_parent(var = "z")
print(test)
#function(x) {
# x get(var)
# }
#<bytecode: 0x5654f7eac430>
#<environment: 0x5654f7637bb8>
test(4)
#[1] 14
The value of z is not stored in the test function, only the name is.
z = 20
test(4)
[1] 24
But is you want to see how that happens you need to look at the environment itself since the body was not evaluated:
> test
function(x) {
x get(var)
}
<bytecode: 0x5654f7eac430>
<environment: 0x5654f7637bb8>
> environment(test)$var
[1] "z"
I was a bit surprised that substituting "x" for the value of var succeeded, but I wasn't suprised that using an object name that I knew was in my workspace did work:
> environment(test)$var <- "x"
> test(4)
[1] 8
> x # only existed in the parameter list but was stored in the environment
Error: object 'x' not found
> environment(test)$var <- "y"
> test(4)
[1] 10
CodePudding user response:
One way to modify functions inside a factory is to use the base function body. As the input is a character here, as.name is used. If fun_parent(y), without the string, is required, replace as.name with substitute.
fun_parent <- function(var) {
fun_child = function(x) x var
body(fun_child)[[3]] <- as.name(var)
fun_child
}
y = 3
test = fun_parent("y")
test(1)
[1] 4
In this case this approach is likely not the best solution, as pointed out by Dan Adams above. I would add to that that the created function is impure - it relies on scoping to find an y, which may lead to unintended behavior.
CodePudding user response:
I asked a related but not identical question here. Here are two options using bquote:
f <- function(varname) {
removeSource(eval(bquote(function(x) x .(as.name(varname)))))
}
f("y")
function (x)
x y
<environment: 0x1128976b0>
op <- options(keep.source = FALSE)
g <- function(varname) {
eval(bquote(function(x) x .(as.name(varname))))
}
options(op)
g("y")
function (x)
x y
<environment: 0x110491580>
