Is it possible to have `dput` return source code that would run outside of the enclosing environment?

0

Issue

Suppose I have a closure add_y(y) which returns a function that adds y to its input.

add_y <- function(y) {
  function(x) {
    x + y
  }
}
add_4 <- add_y(4)

So the value of add_4 is a function that adds 4 to its input. This works. I would like to be use dput to show the definition of add_4 as

function(x) {
  x + 4
}

but this is not what dput returns.

add_y <- function(y) {
  function(x) {
    x + y
  }
}
add_4 <- add_y(4)
dput(add_4)
#> function (x) 
#> {
#>     x + y
#> }

Is there a way to obtain source code that would run outside of the enclosing environment?

Solution

If you control add_y then a workaround would be either to inject the value of y right into the body of the inner function or else inject it into the formal argument list. That eliminates the use of environments so the problem no longer exists. This involves naming the anonymous inner function and only one extra line to perform the injection plus one line to return the result.

# 1. inject into body
add_y2 <- function(y) {
  inner <- function(x) {
    x + y
  }
  body(inner) <- do.call("substitute", list(body(inner)))
  inner
}
# test
add_4 <- add_y2(4)
dput(add_4)
## function (x) 
## {
##     x + 4
## }

# 2. inject into formal arguments
add_y3 <- function(y) {
  inner <- function(x) {
    x + y
  }
  formals(inner)$y <- y
  inner
}
# test
add_4 <- add_y3(4)
dput(add_4)
## function (x, y = 4) 
## {
##     x + y
## }

Answered By – G. Grothendieck

This Answer collected from stackoverflow, is licensed under cc by-sa 2.5 , cc by-sa 3.0 and cc by-sa 4.0

Leave A Reply

Your email address will not be published.

This website uses cookies to improve your experience. We'll assume you're ok with this, but you can opt-out if you wish. Accept Read More