r - 延迟表达式评估而不使用 `quote`

标签 r lazy-evaluation

我创建了以下函数/示例作为在表格等中显示变量标签的通用方式:

#' Function to prettify the output of another function using a `var.labels` attribute
#' This is particularly useful in combination with read.dta et al.
#' @param dat A data.frame with attr `var.labels` giving descriptions of variables
#' @param expr An expression to evaluate with pretty var.labels
#' @return The result of the expression, with variable names replaced with their labels
#' @examples
#' testDF <- data.frame( a=seq(10),b=runif(10),c=rnorm(10) )
#' attr(testDF,"var.labels") <- c("Identifier","Important Data","Lies, Damn Lies, Statistics")
#' prettify( testDF, quote(str(dat)) )
prettify <- function( dat, expr ) {
  labels <- attr(dat,"var.labels")
  for(i in seq(ncol(dat))) colnames(dat)[i] <- labels[i]
  attr(dat,"var.labels") <- NULL
  eval( expr )
}

但是,我宁愿用户不必引用传入的表达式。
replicate这样做,使用此代码:
eval.parent(substitute(function(...) expr))

然而,我不明白它是如何工作的,正如在不理解的情况下尝试复制的典型情况一样,我试图简单地复制此代码或对其进行修补的尝试都失败了。

如何使用未计算的表达式作为输入编写函数,而不要求用户 quote他们的表情?我认为答案将在很大程度上依赖于惰性评估。

最佳答案

用 eval 和替换回答

我认为在这种情况下要做到这一点,您只需要 eval(substitute(expr)) . expr是一个promise,我们可以通过使用expr来获取promise的值。直接或 promise 的内容,通过使用 substitute .见 http://cran.r-project.org/doc/manuals/R-lang.html#Promise-objects详情。 promise 的内容是call ,所以我们只是 eval以获得新的结果。

prettify <- function( dat, expr ) {
  labels <- attr(dat,"var.labels")
  for(i in seq(ncol(dat))) colnames(dat)[i] <- labels[i]
  attr(dat,"var.labels") <- NULL
  eval(substitute(expr))
}

> prettify( testDF, str(dat))
'data.frame':   10 obs. of  3 variables:
 $ Identifier                 : int  1 2 3 4 5 6 7 8 9 10
 $ Important Data             : num  0.336 0.9479 0.1379 0.94 0.0484 ...
 $ Lies, Damn Lies, Statistics: num  1.398 0.654 0.268 -0.397 -0.41 ...

在建议的编辑中,@user2103369 建议 replicate不同,因为它使用 sapply获得多个评估,所以它需要一个函数而不是一个调用。

默认参数时的不同行为

有趣的是,promise 的行为取决于参数是默认参数还是用户添加的;见下文。我认为 SoDA 解决了这个问题,但我手边没有它。此函数打印 promise 的值,并使用 eval 对其进行评估。 ,然后直接求值。
foo <- function(a, b=a+1) {
  print(substitute(b))
  print(eval(substitute(b)))
  b
}

当用户提供值时,直接评估它会导致错误。
> foo(a=2, b=a+1)
a + 1
[1] 3
Error in foo(a = 2, b = a + 1) : object 'a' not found

但默认值有效。
> foo(a=2)
a + 1
[1] 3
[1] 3

在建议的编辑中,@user2103369 说默认参数是在函数内部计算的,而显式参数是在调用框架中计算的。所以在这种情况下,用户提供的值失败了,因为 a在调用框架中不可见。

使用函数的另一种方法

然而,对我来说(尽管 OP 不同意;我将把这部分留给这个答案的 future 读者),这感觉就像使用函数作为第二个参数更自然的情况,像这样;一方面,这意味着用户不必知道它被称为 dat函数内。
prettify <- function( dat, FUN ) {
  f <- match.fun(FUN)
  labels <- attr(dat,"var.labels")
  for(i in seq(ncol(dat))) colnames(dat)[i] <- labels[i]
  attr(dat,"var.labels") <- NULL
  f(dat)
}

然后可以使用匿名函数调用它,我认为这正是您正在寻找的,除了用户必须输入 function(x)以及。
> prettify( testDF, function(x) str(x) )
'data.frame':   10 obs. of  3 variables:
 $ Identifier                 : int  1 2 3 4 5 6 7 8 9 10
 $ Important Data             : num  0.296 0.707 0.883 0.821 0.724 ...
 $ Lies, Damn Lies, Statistics: num  -1.1506 0.4846 -1.824 -0.397 0.0898 ...

或者在简单的情况下,就像你的例子一样,只有函数的名称。
> prettify( testDF, str)
'data.frame':   10 obs. of  3 variables:
 $ Identifier                 : int  1 2 3 4 5 6 7 8 9 10
 $ Important Data             : num  0.296 0.707 0.883 0.821 0.724 ...
 $ Lies, Damn Lies, Statistics: num  -1.1506 0.4846 -1.824 -0.397 0.0898 ...

关于r - 延迟表达式评估而不使用 `quote`,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15039599/

相关文章:

r - 使用 np 包的 R 中二维概率密度函数的一维条件切片

python - 用于遍历 NumPy 数组的惰性求值

javascript - 表达式的 Angular 惰性一次性绑定(bind)

删除连续字符运行中的重复项

r - vapply 中的 FUN.VALUE 参数

r - Wordcloud 不会随着 Shiny 中的新输入进行更新

nhibernate 延迟加载选项

java - flatMap 的方法级通用类型

c++11 - 因式分解 Eigen3 临时值以提高计算速度

r - 在 ggplot2 中绘制累积计数