是否有可能在封闭环境之外获得 运行 的 `dput` return 源代码?
Is it possible to have `dput` return source code that would run outside of the enclosing environment?
假设我有一个闭包 add_y(y)
,其中 returns 一个将 y
添加到其输入的函数。
add_y <- function(y) {
function(x) {
x + y
}
}
add_4 <- add_y(4)
所以add_4
的值是一个将输入加4的函数。这行得通。我想使用 dput
将 add_4
的定义显示为
function(x) {
x + 4
}
但这不是输出 returns.
add_y <- function(y) {
function(x) {
x + y
}
}
add_4 <- add_y(4)
dput(add_4)
#> function (x)
#> {
#> x + y
#> }
有没有办法在封闭环境之外获得 运行 的源代码?
不带 dput()
,不。 dput()
函数不会创建环境的文本表示。
如果要保存函数,可以
save(add_4, file="add4.Rdata")
然后在另一个 R 会话中
load("add4.Rdata")
这将捕获所有包含的值,并且您的函数将像以前一样运行
这可行,但它涉及更改 add_y
的内容。
library(rlang)
library(magrittr)
library(stringr)
add_y <- function(y) {
fn <- expr(function(x) {
x+!!y
})
fn <- deparse(fn) %>% str_c(collapse = "")
fn <- eval(parse(text = fn))
}
add_4 <- add_y(4)
dput(add_4)
#> function (x)
#> {
#> x + 4
#> }
由 reprex package (v2.0.1)
于 2021-12-24 创建
您可以构建一个 dput
替换,生成代码来创建类似 add_4
的函数,但它不会按照您想要的方式解析:
dput_with_env <- function(f) {
fn <- deparse(f, control = c("keepNA", "keepInteger",
"niceNames", "showAttributes"))
env <- as.list(environment(f))
cat("local({ f =\n")
cat(fn, sep = "\n")
cat("\nenvironment(f) <- list2env(\n")
dput(env)
cat(")\nf})")
}
add_y <- function(y) {
function(x) {
x + y
}
}
add_4 <- add_y(4)
dput_with_env(add_4)
#> local({ f =
#> function (x)
#> {
#> x + y
#> }
#>
#> environment(f) <- list2env(
#> list(y = 4)
#> )
#> f})
由 reprex package (v2.0.1)
于 2021-12-24 创建
这假设 add_4
的环境非常简单,因此其环境的父级可以是您评估代码时的环境。我们可以试试看:
newfn <- local({ f =
function (x)
{
x + y
}
environment(f) <- list2env(
list(y = 4)
)
f})
newfn
#> function (x)
#> {
#> x + y
#> }
#> <environment: 0x7f9a1b5e2318>
newfn(1)
#> [1] 5
由 reprex package (v2.0.1)
于 2021-12-24 创建
如果您控制 add_y,那么解决方法是将 y 的值直接注入到内部函数的主体中,或者将其注入到正式参数列表中。这消除了环境的使用,因此问题不再存在。这涉及命名匿名内部函数,并且只有一行额外的行来执行注入加上一行 return 结果。
# 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
## }
假设我有一个闭包 add_y(y)
,其中 returns 一个将 y
添加到其输入的函数。
add_y <- function(y) {
function(x) {
x + y
}
}
add_4 <- add_y(4)
所以add_4
的值是一个将输入加4的函数。这行得通。我想使用 dput
将 add_4
的定义显示为
function(x) {
x + 4
}
但这不是输出 returns.
add_y <- function(y) {
function(x) {
x + y
}
}
add_4 <- add_y(4)
dput(add_4)
#> function (x)
#> {
#> x + y
#> }
有没有办法在封闭环境之外获得 运行 的源代码?
不带 dput()
,不。 dput()
函数不会创建环境的文本表示。
如果要保存函数,可以
save(add_4, file="add4.Rdata")
然后在另一个 R 会话中
load("add4.Rdata")
这将捕获所有包含的值,并且您的函数将像以前一样运行
这可行,但它涉及更改 add_y
的内容。
library(rlang)
library(magrittr)
library(stringr)
add_y <- function(y) {
fn <- expr(function(x) {
x+!!y
})
fn <- deparse(fn) %>% str_c(collapse = "")
fn <- eval(parse(text = fn))
}
add_4 <- add_y(4)
dput(add_4)
#> function (x)
#> {
#> x + 4
#> }
由 reprex package (v2.0.1)
于 2021-12-24 创建您可以构建一个 dput
替换,生成代码来创建类似 add_4
的函数,但它不会按照您想要的方式解析:
dput_with_env <- function(f) {
fn <- deparse(f, control = c("keepNA", "keepInteger",
"niceNames", "showAttributes"))
env <- as.list(environment(f))
cat("local({ f =\n")
cat(fn, sep = "\n")
cat("\nenvironment(f) <- list2env(\n")
dput(env)
cat(")\nf})")
}
add_y <- function(y) {
function(x) {
x + y
}
}
add_4 <- add_y(4)
dput_with_env(add_4)
#> local({ f =
#> function (x)
#> {
#> x + y
#> }
#>
#> environment(f) <- list2env(
#> list(y = 4)
#> )
#> f})
由 reprex package (v2.0.1)
于 2021-12-24 创建这假设 add_4
的环境非常简单,因此其环境的父级可以是您评估代码时的环境。我们可以试试看:
newfn <- local({ f =
function (x)
{
x + y
}
environment(f) <- list2env(
list(y = 4)
)
f})
newfn
#> function (x)
#> {
#> x + y
#> }
#> <environment: 0x7f9a1b5e2318>
newfn(1)
#> [1] 5
由 reprex package (v2.0.1)
于 2021-12-24 创建如果您控制 add_y,那么解决方法是将 y 的值直接注入到内部函数的主体中,或者将其注入到正式参数列表中。这消除了环境的使用,因此问题不再存在。这涉及命名匿名内部函数,并且只有一行额外的行来执行注入加上一行 return 结果。
# 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
## }