列表中的 rlang 表达式作为函数的参数
rlang Expressions in List as Args to Function
我正在尝试将用户输入解析为函数调用的参数(在表达式中)。好像我很接近但是!将我的论点包装在括号中,这是行不通的。我正在尝试使用用户输入重新创建以下内容:
recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>%
step_log(disp, base = 10, offset = 0) %>%
prep()
library(rlang)
library(tidymodels)
user_dv <- "mpg"
user_idv <- c("cyl", "hp", "wt", "disp")
user_step <- "log"
user_selector <- "disp"
user_args <- "base = 10, offset = 0"
formula <- as.formula(paste(user_dv, paste(user_idv, collapse = " + "), sep = " ~ "))
rcp <- expr(recipe(!!formula,data = mtcars))
add_step <- function(x, step, selector, args){
f <- parse_expr(paste0("step_", step))
vars <- ensym(user_selector)
args <- args %>%
str_replace(",", ";") %>%
parse_exprs()
step_expr <- call2(f, vars, !!!args)
expr(!!x %>% !!step_expr)
}
rcp %>%
add_step(user_step, user_selector, user_args) %>%
eval() %>%
prep()
我的表情最终变成了这样:
recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>%
step_log(disp, (base = 10), (offset = 0))
哪个不准备()
在 parse_exprs()
之后,您最终得到存储在未命名列表中的赋值表达式:
# [[1]]
# base = 10
#
# [[2]]
# offset = 0
同时,要使用 !!!
获得您想要的效果,它们需要是命名列表中的值:
# $base
# [1] 10
#
# $offset
# [1] 0
话虽如此,我建议改为“转发点”,因为它会导致更简单、更灵活的实施:
add_step <- function(x, step, selector, ...){
f <- parse_expr(paste0("step_", step))
vars <- sym(selector)
step_expr <- call2(f, vars, ...) # <---- forwarding the dots here
expr(!!x %>% !!step_expr)
}
用户现在可以简单地直接向 add_step()
提供所需的参数:
rcp %>% add_step(user_step, user_selector, base=10, offset=0)
# recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>%
# step_log(disp, base = 10, offset = 0)
或者将它们存储在列表中并在你的函数上使用!!!
:
user_args <- list(base = 10, offset=0)
rcp %>% add_step(user_step, user_selector, !!!user_args)
我正在尝试将用户输入解析为函数调用的参数(在表达式中)。好像我很接近但是!将我的论点包装在括号中,这是行不通的。我正在尝试使用用户输入重新创建以下内容:
recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>%
step_log(disp, base = 10, offset = 0) %>%
prep()
library(rlang)
library(tidymodels)
user_dv <- "mpg"
user_idv <- c("cyl", "hp", "wt", "disp")
user_step <- "log"
user_selector <- "disp"
user_args <- "base = 10, offset = 0"
formula <- as.formula(paste(user_dv, paste(user_idv, collapse = " + "), sep = " ~ "))
rcp <- expr(recipe(!!formula,data = mtcars))
add_step <- function(x, step, selector, args){
f <- parse_expr(paste0("step_", step))
vars <- ensym(user_selector)
args <- args %>%
str_replace(",", ";") %>%
parse_exprs()
step_expr <- call2(f, vars, !!!args)
expr(!!x %>% !!step_expr)
}
rcp %>%
add_step(user_step, user_selector, user_args) %>%
eval() %>%
prep()
我的表情最终变成了这样:
recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>%
step_log(disp, (base = 10), (offset = 0))
哪个不准备()
在 parse_exprs()
之后,您最终得到存储在未命名列表中的赋值表达式:
# [[1]]
# base = 10
#
# [[2]]
# offset = 0
同时,要使用 !!!
获得您想要的效果,它们需要是命名列表中的值:
# $base
# [1] 10
#
# $offset
# [1] 0
话虽如此,我建议改为“转发点”,因为它会导致更简单、更灵活的实施:
add_step <- function(x, step, selector, ...){
f <- parse_expr(paste0("step_", step))
vars <- sym(selector)
step_expr <- call2(f, vars, ...) # <---- forwarding the dots here
expr(!!x %>% !!step_expr)
}
用户现在可以简单地直接向 add_step()
提供所需的参数:
rcp %>% add_step(user_step, user_selector, base=10, offset=0)
# recipe(mpg ~ cyl + hp + wt + disp, data = mtcars) %>%
# step_log(disp, base = 10, offset = 0)
或者将它们存储在列表中并在你的函数上使用!!!
:
user_args <- list(base = 10, offset=0)
rcp %>% add_step(user_step, user_selector, !!!user_args)