【问题标题】:R reverse behaviour of bquoteR bquote的反向行为
【发布时间】:2018-06-11 16:59:36
【问题描述】:

bquote 函数允许评估被包裹在.() 调用中的表达式部分。例如,

a <- 2
b <- 100
bquote(.(2 * a) * x + .(log10(b)))

会返回

4 * x + 2

我想重写这个函数来评估除.() 调用中的内容之外的所有内容。这是期望的行为:

a <- 2
b <- 100
bquote(2 * a * .(x) + log10(b))

> 4 * x + 2

我知道要这样做,我必须检查 abstract syntax tree 并在没有 .() 调用的情况下评估早午餐,但我无法处理所有这些递归。

你能帮我写一个这样的函数吗?

【问题讨论】:

  • 是否有用例来证明另一种新语法的合理性?它怎么知道评估第一个* 而不是第二个或+
  • 也许你可以退一步说一下拥有这样一个功能的目标是什么。
  • 这样做的原因是在绘图之前简化计算机生成的方程。

标签: r metaprogramming


【解决方案1】:

subst 将替换除 .(...) 内的所有变量之外的所有变量,simplify 函数将简化没有变量的子树——如果不需要简化,则省略简化部分。没有使用任何包。

subst <- function(e) {
   if (typeof(e) == "language") {
      if (identical(e[[1]], as.name("."))) e[[2]]
      else {
        if (length(e) > 1) e[-1] <- lapply(as.list(e[-1]), subst)
        e
      }
   } else {
      eval(e)
   }
}

simplify <- function(e) {
  if (typeof(e) == "language") {
     if (length(all.vars(e))) {
         if (length(e) > 1) {
           e[-1] <- lapply(as.list(e[-1]), simplify)
           e
         } else e
     } else eval(e)
  } else e
}

inverse_bquote <- function(x, SIMPLIFY = TRUE) {
   result <- subst(substitute(x))
   if (SIMPLIFY) simplify(result) else result
}

现在测试一下。

a <- 2
b <- 100

inverse_bquote(2 * a * .(x) + log10(b))
## 4 * x + 2

# without simplification

inverse_bquote(2 * a * .(x) + log10(b), SIMPLIFY = FALSE)
## 2 * 2 * x + log10(100)

更新:增加了简化。让它成为可选的。

【讨论】:

    猜你喜欢
    • 2015-10-03
    • 2015-12-29
    • 2014-03-20
    • 1970-01-01
    • 1970-01-01
    • 2018-09-11
    • 2014-12-13
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多