I want to create a function that returns another function with a parameter from the former, e.g.
foo1 <- function(y) function(x) x+y
(Edit: I wrote foo1 <- function(y) function(x+y)
originally, changed this. Also, see the answer of @Konrad Rudolph as to why this is a bad definition.)
but! I would like to be able to see what parameter value 'y' was chosen. The above prints like
foo1(1.2)
#> function(x) x + y
#> <environment: 0x000001dd24275a90>
Now, I could achieve this through
foo2 <- function(y){
eval(parse(text = sprintf("function(x) x + %s", y)))
}
Then printing 'foo2' shows what parameter value 'y' was used in its creation
foo2(1.2)
#> function(x) x + 1.2
#> <environment: 0x000001dd242604a0>
However, I suspect there is a more elegant solution.
I thought something like
foo3 <- function(y){
eval(substitute(function(x) x+dummy, env = list(dummy=y)))
}
could work, but no. That will print
foo3(1.2)
#> function(x) x+dummy
#> <environment: 0x000001dd23e137d0>
Does anyone have a more elegant solution than my 'foo2'?
First of all, beware that your original function is broken (beyond the syntax error):
foo1 <- function(y) function(x) x+y
a <- 10
myfoo <- foo1(a)
a <- 20
myfoo(1)
# [1] 21
You probably wanted the last call to return 11, not 21.
To fix this, we need to force eager evaluation of y
- otherwise it will be lazily evaluated when it’s used, and not before:
foo1 <- function (y) {
force(y)
function (x) x + y
}
Next, to answer your actual question: your foo3
almost works! R just tricks you, because it stores the “source code” of the function in an attribute (srcref
) of the function. And when displaying the function definition via print
, it prints that srcref
(if available) instead of the actual body. We can delete the attribute to fix that:
foo <- function (y) {
fun <- eval(substitute(function(x) x + dummy, env = list(dummy = y)))
attr(fun, 'srcref') <- NULL
fun
}
foo(1.2)
# x + 1.2
# <environment: 0x108952138>
(Note that we don’t need to explicitly force evaluation of y
in this definition of foo()
, since passing it to list()
(and then to substitute()
) will cause it to be evaluated anyway.)