我试图调整函数内部参数的名称。我想创建一个程序,它接受函数体,查找 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 的最终输出是字符向量而不是调用。我现在怎样才能将此更改回电话?
提前致谢!
答案 0 :(得分:1)
当然,有一种更好的方法可以做你想做的事情,而不需要修改功能。话虽这么说,你绝对不想用正则表达式替换变量,这可能有各种各样的问题。通常,尝试将代码作为字符串进行操作会导致问题,例如像tricky <- function(x, y) { tst <- "x + y"; -xx*x + yy*y }
这样的函数,其中字符串和变量名称重叠,将导致错误的结果。
这是一个采用递归方法(Recall
)来遍历表达式树的函数(使用&#39;堆栈类型结构可以避免递归,但对我来说似乎更难)
## 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
# }
#
答案 1 :(得分:0)
有几种方法可以去这里。按照你的代码,我会用这样的东西:
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)