1

I have a function that produces a function:

fun1 <- function (x)
    return (function() x)

By the time a function is produced, the value of x is already basically a constant:

fun2 <- fun1 ("a")

However, when I have fun2 printed, it won't show the actual value, it only shows "x" even though it is by now obsolete:

> fun2
function() x
<environment: 0x55a9f94f9fc8>

How can I force the evaluation of x so that fun2 gets printed as

function() "a"

or however it was produced?

Kamil S.
  • 406
  • 3
  • 10

2 Answers2

4

There's no need to resort to deparse here. You can write the evaluated value of x into the body of the newly created function:

fun1 <- function (x){
  f <- function() x
  body(f) <- x
  f
}

So that:

fun1("a")
#> function () 
#> "a"
#> <environment: 0x00000146d0449dd8>

and

f <- fun1("a")
f()
#> [1] "a"

EDIT

If you wanted f to take an argument you could do:

fun1 <- function (x){
  f <- function(y) y + x
  body(f)[[3]] <- x
  f
}

so that

fun1(3)
#> function (y) 
#> y + 3
#> <environment: 0x00000146d4b702a0>
Allan Cameron
  • 147,086
  • 7
  • 49
  • 87
  • Thanks, but it seems that my minimal example was too minimal. I'd like `f` to take an argument, and I'd like to be able to use that argument inside the body of `f`. I've only managed to do it by enclosing the body of `f` in an `expression`, but then I'm back to square one. Say I'd like `f` to be `function(y) y+x`, and then `fun1(1)` to be printed as `function(y) y+1`. – Kamil S. Sep 27 '20 at 10:51
  • Wonderful, thanks a lot! If you're very pedantic, `y` is missing from the declaration of `f` inside `fun1`. – Kamil S. Sep 27 '20 at 11:53
  • 1
    @KamilS. I _am_ very pedantic. Now fixed. Thanks! – Allan Cameron Sep 27 '20 at 11:59
1

This substitutes all instances of x in the body of fun. In the example fun1 has one argument but it would continue to work with multiple fun1 arguments used in fun substituting them all into fun. We have also set the environment of fun to the environment in the caller of fun1 allowing the caller to change that by specifying envir if needed.

fun1 <- function (x, envir = parent.frame()) {
    fun <- function() x
    body(fun) <- do.call("substitute", list(body(fun)))
    environment(fun) <- envir
    fun
}

fun2 <- fun1("a")
fun2
## function () 
## "a"

environment(fun2)
## <environment: R_GlobalEnv>
G. Grothendieck
  • 254,981
  • 17
  • 203
  • 341
  • Thank you. This would have been more useful as it's more general but when I use something like `tmp[1]` inside `fun`, this puts the entire `tmp` into `fun` and just adds `[1]` at the end. But don't trouble yourself, I only have two elements to replace so it's not a problem doing it manually one by one like in Allan's solution. – Kamil S. Sep 28 '20 at 16:00