Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

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

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?

like image 565
crf Avatar asked Dec 24 '21 19:12

crf


1 Answers

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
## }
like image 163
G. Grothendieck Avatar answered Nov 15 '22 00:11

G. Grothendieck