【问题标题】:Substitute formal arguments in a function factory r在函数工厂 r 中替换形式参数
【发布时间】:2017-08-23 17:59:54
【问题描述】:

我正在尝试创建一个函数工厂来创建具有自定义形式参数名称的函数。这个想法是向工厂提供一个字符串,工厂反过来在形式和返回的函数体中替换它。我已经设法使用 eval(parse(text=paste())) 来做到这一点,但我在其他地方读到了这种不好的做法。如何在避免进行 evalparse 的同时获得相同的输出?

MyLinearRateFunctions<-function(varX){

  eval(parse(text=paste("function(a,b,",
                    varX,
                    ") 1/(a + b*",
                    varX,
                    ")",sep="")
  ))

 }

(LinearRateMPG<-MyLinearRateFunctions('mpg'))

# function(a,b,mpg) 1/(a + b*mpg)
# <environment: 0x11c2f2a00>

(LinearRateCYL<-MyLinearRateFunctions('cyl'))

# function(a,b,cyl) 1/(a + b*cyl)
# <environment: 0x11e4cb908>

(LinearRateDISP<-MyLinearRateFunctions('disp'))

# function(a,b,disp) 1/(a + b*disp)
# <environment: 0x11e47eae8>

【问题讨论】:

    标签: r metaprogramming


    【解决方案1】:

    可能有一种更简洁的方法可以到达那里,但这里有一个想法:

    fn <- function(x) {
        f <- eval(bquote(function(a, b) 1 / (a + b * .(as.name(x)))))
        formals(f) <- c(formals(f), setNames(alist(dummy = ), x))
        f
    }
    

    在fn() 的第一行,我们使用bquote() 将x 替换为数学表达式。我们需要评估它(使用eval())以将其从调用转换为函数。然后在第二行中,我们将第三个参数添加到形式参数列表中。最后一行返回函数。

    fn("mpg")
    # function (a, b, mpg) 
    # 1/(a + b * mpg)
    # <environment: 0x4f05c78>
    
    fn("cyl")
    # function (a, b, cyl) 
    # 1/(a + b * cyl)
    # <environment: 0x4f9ba28>
    

    快速检查:

    fn("mpg")(1, 2, 3)
    # [1] 0.1428571
    1 / (1 + 2 * 3)
    # [1] 0.1428571
    

    感谢您要求eval(parse(text = ...)) 的更好替代方案,这绝对是不好的做法。

    【讨论】:

    • 如果需要,可以在eval()中更改功能环境。
    【解决方案2】:

    这是使用pryr::make_function 的替代方法。这具有将函数“环境”设置为“函数工厂”调用的调用环境的额外好处

    fn2 <- function(x) {
      fbody <- bquote(1 / (a + b * .(as.name(x))))
      fargs <- setNames(alist(,,),c('a','b',x))
      pryr::make_function(fargs,fbody, env=parent.frame(2))
    }
    

    虽然这看起来避免了对 eval 的调用,但它只是隐藏在 make_function 中

    【讨论】:

      【解决方案3】:

      这仅使用基数 R 而没有 eval。首先设置一个函数作为模板使用,然后更改形式,设置主体,设置环境。

      factory <- function(x, envir = parent.frame()) {
        fun <- function(a, b, x) {}
        names(formals(fun))[[3]] <- x
        body(fun) <- substitute(1/(a+b*x), list(x = as.name(x)))
        environment(fun) <- envir
        fun
      }
      
      # test
      myfun <- factory("m")
      

      给予:

      > myfun
      function (a, b, m) 
      1/(a + b * m)
      

      【讨论】:

        猜你喜欢
        • 2022-11-04
        • 2013-11-14
        • 2020-11-28
        • 1970-01-01
        • 2011-06-08
        • 2021-12-05
        • 1970-01-01
        • 2016-04-20
        • 2015-06-04
        相关资源
        最近更新 更多