【问题标题】:Modify a function call captured in exp修改 exp 中捕获的函数调用
【发布时间】:2018-06-10 14:49:19
【问题描述】:

例如,将expr(cumsum(1:3))的输出中的cumsum更改为cumprod

目前我唯一能想到的是将expr(cumsum(1:3)) 的输出转换为字符串,对其进行编辑,然后将其改回函数调用。

不过,这似乎是一个非常糟糕的解决方案,我正在努力寻找更好的方法。

library(rlang) 
f(expr(cumsum(1:4)), cumprod)
# [1] 1 2 6 24

这基本上就是我想要实现的目标。你能帮我找到一个起点吗?

【问题讨论】:

  • 我不清楚你如何决定要替换哪个函数(因为: 也是一个函数)。但是如果你想总是替换外部的,你可以定义下面的函数f <- function(x, y) {tmp <- substitute(x) ; tmp[1] <- substitute(y) ; eval(tmp)}然后使用它如下f(cumsum(1:4), cumprod())
  • @DavidArenburg ;如果你使用tmp[[1]] ,你可以避免()
  • @user20650 好点。
  • @DavidArenburg 谢谢!这正是我希望找到的!

标签: r functional-programming metaprogramming


【解决方案1】:

如果您只是将gsub 应用于表达式,R 会将其转换为字符向量并进行替换,您可以使用parse 将其转换为表达式:

y <- 1:4
x <- expression({cumsum(y)})

x.2 <- gsub("cumsum", "cumprod", x)
class(x.2)
# [1] "character"
x.2 <- parse(text = x.2)
eval(x)
# [1]  1  3  6 10
eval(x.2)
# [1]  1  2  6 24

【讨论】:

    【解决方案2】:

    这是一个使用rlang的选项

    f <- function(ex, fn) {
    
       ex1 <- as.character(ex)
       fn <- enquo(fn)[-1]
       eval_tidy(parse_expr(glue::glue('{fn}({ex1[-1]})')))
    
       }
    f(expr(cumsum(1:4)), cumprod)
    #[1]  1  2  6 24
    

    【讨论】:

      【解决方案3】:

      请注意,如果您将 cumsum 替换为 cumprod,则输出将是一个长度为 4 的向量,而不是 24,因此我们假设您打算将其替换为 prod

      我们使用substitutecumsum 替换为cumsum 参数的值,然后计算结果表达式。

      f 这里不使用任何包——问题中的输入使用来自 rlang 的 expr,但即使这样也不是真正需要的,因为我们可以使用 quote(...) 代替 expr(...)

      f <- function(.x, cumsum) eval.parent(do.call("substitute", list(.x)))
      
      # test
      f(expr(cumsum(1:4)), prod)
      ## [1] 24
      
      f(expr(cumsum(1:4)), cumprod)
      ## [1]  1  2  6 24
      

      【讨论】:

        【解决方案4】:

        我喜欢@David Arenburg,所以我在这里发布他的答案并标记它。

        我不清楚你如何决定要替换哪个函数(因为 : 也是一个函数)。但是如果你想总是替换外部的,你可以定义以下

        function f <- function(x, y) {
          tmp <- substitute(x) 
          tmp[[1]] <- substitute(y)  
          eval(tmp)
         }
        

        然后按如下方式使用

        f(cumsum(1:4), cumprod) 
        #[1] 1 2 6 24
        

        – 大卫·阿伦伯格

        【讨论】:

          猜你喜欢
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2019-08-21
          • 1970-01-01
          • 1970-01-01
          • 2019-02-17
          • 1970-01-01
          相关资源
          最近更新 更多