R装饰器改变输入和输出

时间:2014-04-17 03:31:50

标签: r decorator

我正在尝试重构这个。在Python中,我会使用装饰器。什么是'糟糕的方式来做到这一点?说,我们有这种模式

good_input <- format_input( bad_input )
bad_output <- use_this_func( good_input )
good_output <- format_output( bad_output )

然后再次,

good_input <- format_input( bad_input )
bad_output <- use_this_other_func( good_input )
good_output <- format_output( bad_output )

你可以想象,它会像野生蘑菇一样繁殖。我想要一些接近这个解决方案的东西

use_this_robust_func <- wrapper( use_this_func ) # Or wrapper( use_this_other_func )
good_output <- use_this_robust_func( bad_input )

我正在尝试将use_this_funcuse_this_other_func(和相关函数)的调用与format_inputformat_output打包在一起。部分使用此question,到目前为止我已经

wrapper <- function( func_not_robust ){
  func_robust <- function( ... ){
   # This is the bit I haven't figured out
   ... format_input( ) ... # supposed to convert bad input - the function argument - to good
   bad_output <- func_not_robust( ... ) # supposed to take good input as argument
   good_output <- format_output( bad_output )
   return( good_output )
   }
  return( func_robust )
}

抱歉伪代码。注意我不确定这是进入R的方法。我不是很接近上面解决方案的草图,它是通过将Python翻译成R而生成的.R。R本地人如何做到这一点?提前谢谢。

1 个答案:

答案 0 :(得分:6)

我认为你几乎就在那里。这是一个例子,清洁的第一阶段是用NA代替负输入值,输出清理很容易否定一切:

format_input <- function(x){
    x[x<0] <- NA
    return(x)
}

format_output <- function(x){
    return(-x)
}

wrapper <- function(f){
    force(f)
    g = function(bad_input){
        good_input = format_input(bad_input)
        bad_output = f(good_input)
        good_output = format_output(bad_output)
        return(good_output)
    }
    g
}

然后:

> wrapper(sqrt)(c(-2,2))
[1]        NA -1.414214

wrapper(sqrt)返回&#34;闭包&#34;,这是一个包含数据的函数。函数f具有函数sqrt的值作为该机箱的一部分。

需要进行force调用,因为f在创建g时未进行评估,而在某些情况下,如果没有f,则会force赢得&#39}。在运行包装版本时,由于R的懒惰评估或&#34;承诺&#34;或者其他的东西。我几乎不确定何时发生这种情况,但是对闭包生成器的未评估参数添加wrapper <- function(f, fi=format_input, fo=format_output){ force(f) ; force(fi); force(fo) g = function(bad_input){ good_input = fi(bad_input) bad_output = f(good_input) good_output = fo(bad_output) return(good_output) } g } 调用是零开销。它有点像货物编程但从来没有问题。

更灵活的解决方案可能是将输入和输出清理函数指定为闭包生成器的函数,默认值为:

sqrt

然后我可以使用不同的输入和输出格式化程序包装> make_pos = function(x){abs(x)} > wrapper(sqrt,fo=make_pos)(c(-2,2)) [1] NA 1.414214 。例如,用正面函数改变负面函数:

format_output(sqrt(format_output(bad_input)))

更灵活的解决方案是发现您在此处生成功能链。您的输出为functional。这是函数组合> require(functional) > w = Compose(format_input, sqrt, format_output) > w(c(-2,2)) [1] NA -1.414214 包中有一个函数来执行此操作:

do.call

如果你的合成中有三个以上的函数,这可能会更有用,例如你可以使用{{1}}编写一个函数列表并将它们组合在一起....

一旦你看到函数式编程中的模式,就会让人上瘾。我现在停下来。