0

问题描述

Sys.setenv没有简单的接口来提供 LHS(环境变量名称)作为参数。如果想要动态定义应该设置什么环境变量,那么就需要元编程方法。

基础 R 方式

这个小辅助函数按预期工作。

setenv = function(var, value, quiet=TRUE) {
  stopifnot(is.character(var), !is.na(var), length(value)==1L, is.atomic(value))
  qc = as.call(c(list(quote(Sys.setenv)), setNames(list(value), var)))
  if (!quiet) print(qc)
  eval(qc)
}

var_name = "RISCOOL"
Sys.getenv(var_name)
#[1] ""
setenv(var_name, value=150, quiet=FALSE)
#Sys.setenv(RISCOOL = 150)
Sys.getenv(var_name)
#[1] "150"

问题

问题是如何使用pryrrlang( tidyeval) 之类的包来解决问题?或者最终是另一个流行的。
我根本不知道这些包,并希望更好地了解它们如何简化我的元编程代码。

请注意,问题是关于元编程的,设置 env var 只是一个例子。

4

4 回答 4

3

如果你想使用 rlang 风格的 quasiquotation 来构造一个调用并直接评估,你需要blast()

blast <- function(expr, env = caller_env()) {
  eval_bare(enexpr(expr), env)
}

vars <- c(A = "a", B = "b", C = "c")

blast(data.frame(!!!vars))
#>   A B C
#> 1 a b c

在您的原始示例中,您需要取消引用名称。我们尚不支持 LHS 上的深度取消引用:=(请参阅https://github.com/r-lib/rlang/issues/279),但您可以!!!改用:

setenv <- function(var, value) {
  args <- setNames(value, var)
  blast(Sys.setenv(!!!args))
}

setenv("foobar", 1)
#> [1] TRUE

Sys.getenv("foobar")
#> [1] "1"

要插入打印的调用,blast 级别太高,但您可以使用以下组件:

setenv <- function(var, value, quiet = FALSE) {
  args <- setNames(value, var)
  call <- expr(Sys.setenv(!!!args))

  if (!quiet) {
    print(call)
  }

  # Evaluate in our own environment where `Sys.setenv()` is defined
  # (and protected if we're in a package namespace)
  eval(call)
}
于 2019-12-06T08:48:59.407 回答
1

使用do.call

var_name = "RISCOOL"
do.call("Sys.setenv", as.list(setNames(3, var_name)))

# check that it worked
Sys.getenv(var_name)
## [1] "3"

或使用 purrr

library(purrr)
invoke("Sys.setenv", set_names(4, var_name))
于 2019-12-06T03:38:01.947 回答
1

我认为你需要使用:=. 它的用法在其中一个dplyr小插曲中进行了说明,但功能由rlang. 在这种情况下,您可以使用call2

setenv <- function(var, val) {
  rlang::call2("Sys.setenv", !!rlang::enexpr(var) := val)
}

setenv(foo, "bar")
# Sys.setenv(foo = "bar")

只需根据需要添加eval呼叫。

于 2019-12-06T22:39:17.883 回答
0

只需使用do.call.

lst <- structure(list(value), names=name)
do.call(Sys.setenv, lst)
于 2019-12-06T03:37:20.843 回答