在函数 r 中更改参数名称
change argument names inside a function r
我正在尝试调整函数内参数的名称。我想创建一个获取函数主体的过程,查找 x,将每个 x 更改为 x0,然后将函数恢复到原来的样子。举个例子:
f = function(x, y) -x^2 + x + -y^2 + y
# Take old names
form_old = names(formals(f))
# Make new names
form_new = paste0(form_old, 0)
# Give f new formals
formals(f) = setNames(vector("list", length(form_new)), form_new)
# Copy function body
bod = as.list(body(f))
for (i in 1:length(form_new)) {
bod = gsub(form_old[i], form_new[i], bod)
}
# return from list to call ?
body(f) = as.call(list(bod))
f(1, 1) # produces an error
到目前为止,此代码会将所有变量名称从 x 更改为 x0 并从 y 到 y0。但是,bod 的最终输出是字符向量而不是调用。我现在如何将其改回电话?
提前致谢!
有几种方法可以到达这里。按照你的代码,我会用这样的东西:
f = function(x, y) -x^2 + x + -y^2 + y
# Take old names
form_old = names(formals(f))
# Make new names
form_new = paste0(form_old, 0)
deparse(body(f)) -> bod
for (i in 1:length(form_new)) {
bod = gsub(form_old[i], form_new[i], bod, fixed = TRUE)
}
formals(f) = setNames(vector("list", length(form_new)), form_new)
body(f) <- parse(text = bod)
f(1, 1)
当然有更好的方法来做你想做的事情,不需要修改函数。话虽如此,您绝对不想用正则表达式替换变量,这可能会带来各种各样的问题。通常,尝试将代码作为字符串来操作会导致问题,例如,像 tricky <- function(x, y) { tst <- "x + y"; -xx*x + yy*y }
这样的函数,其中字符串和变量名重叠,将导致错误的结果。
这是一个采用递归方法(Recall
)遍历表达式树的函数(使用'stack'类型结构可以避免递归,但对我来说似乎更难)。
## Function to replace variables in function body
## expr is `body(f)`, keyvals is a lookup table for replacements
rep_vars <- function(expr, keyvals) {
if (!length(expr)) return()
for (i in seq_along(expr)) {
if (is.call(expr[[i]])) expr[[i]][-1L] <- Recall(expr[[i]][-1L], keyvals)
if (is.name(expr[[i]]) && deparse(expr[[i]]) %in% names(keyvals))
expr[[i]] <- as.name(keyvals[[deparse(expr[[i]])]])
}
return( expr )
}
## Test it
f <- function(x, y) -x^2 + x + -y^2 + y
newvals <- c('x'='x0', 'y'='y0') # named lookup vector
newbod <- rep_vars(body(f), newvals)
newbod
# -x0^2 + x0 + -y0^2 + y0
## Rename the formals, and update the body
formals(f) <- pairlist(x0=bquote(), y0=bquote())
body(f) <- newbod
## The new 'f'
f
# function (x0, y0)
# -x0^2 + x0 + -y0^2 + y0
f(2, 2)
# [1] -4
使用更难的函数,您希望避免修改字符串或其他名为 yy
和 xx
的变量,例如,
tricky <- function(x, y) { tst <- "x + y"; -xx*x + yy*y }
formals(tricky) <- pairlist(x0=bquote(), y0=bquote())
body(tricky) <- rep_vars(body(tricky), newvals)
tricky
# function (x0, y0)
# {
# tst <- "x + y"
# -xx * x0 + yy * y0
# }
#
我正在尝试调整函数内参数的名称。我想创建一个获取函数主体的过程,查找 x,将每个 x 更改为 x0,然后将函数恢复到原来的样子。举个例子:
f = function(x, y) -x^2 + x + -y^2 + y
# Take old names
form_old = names(formals(f))
# Make new names
form_new = paste0(form_old, 0)
# Give f new formals
formals(f) = setNames(vector("list", length(form_new)), form_new)
# Copy function body
bod = as.list(body(f))
for (i in 1:length(form_new)) {
bod = gsub(form_old[i], form_new[i], bod)
}
# return from list to call ?
body(f) = as.call(list(bod))
f(1, 1) # produces an error
到目前为止,此代码会将所有变量名称从 x 更改为 x0 并从 y 到 y0。但是,bod 的最终输出是字符向量而不是调用。我现在如何将其改回电话?
提前致谢!
有几种方法可以到达这里。按照你的代码,我会用这样的东西:
f = function(x, y) -x^2 + x + -y^2 + y
# Take old names
form_old = names(formals(f))
# Make new names
form_new = paste0(form_old, 0)
deparse(body(f)) -> bod
for (i in 1:length(form_new)) {
bod = gsub(form_old[i], form_new[i], bod, fixed = TRUE)
}
formals(f) = setNames(vector("list", length(form_new)), form_new)
body(f) <- parse(text = bod)
f(1, 1)
当然有更好的方法来做你想做的事情,不需要修改函数。话虽如此,您绝对不想用正则表达式替换变量,这可能会带来各种各样的问题。通常,尝试将代码作为字符串来操作会导致问题,例如,像 tricky <- function(x, y) { tst <- "x + y"; -xx*x + yy*y }
这样的函数,其中字符串和变量名重叠,将导致错误的结果。
这是一个采用递归方法(Recall
)遍历表达式树的函数(使用'stack'类型结构可以避免递归,但对我来说似乎更难)。
## Function to replace variables in function body
## expr is `body(f)`, keyvals is a lookup table for replacements
rep_vars <- function(expr, keyvals) {
if (!length(expr)) return()
for (i in seq_along(expr)) {
if (is.call(expr[[i]])) expr[[i]][-1L] <- Recall(expr[[i]][-1L], keyvals)
if (is.name(expr[[i]]) && deparse(expr[[i]]) %in% names(keyvals))
expr[[i]] <- as.name(keyvals[[deparse(expr[[i]])]])
}
return( expr )
}
## Test it
f <- function(x, y) -x^2 + x + -y^2 + y
newvals <- c('x'='x0', 'y'='y0') # named lookup vector
newbod <- rep_vars(body(f), newvals)
newbod
# -x0^2 + x0 + -y0^2 + y0
## Rename the formals, and update the body
formals(f) <- pairlist(x0=bquote(), y0=bquote())
body(f) <- newbod
## The new 'f'
f
# function (x0, y0)
# -x0^2 + x0 + -y0^2 + y0
f(2, 2)
# [1] -4
使用更难的函数,您希望避免修改字符串或其他名为 yy
和 xx
的变量,例如,
tricky <- function(x, y) { tst <- "x + y"; -xx*x + yy*y }
formals(tricky) <- pairlist(x0=bquote(), y0=bquote())
body(tricky) <- rep_vars(body(tricky), newvals)
tricky
# function (x0, y0)
# {
# tst <- "x + y"
# -xx * x0 + yy * y0
# }
#