【问题标题】:R decorator to change both input and outputR装饰器来改变输入和输出
【发布时间】:2023-03-21 01:26:01
【问题描述】:

我正在尝试重构它。在 Python 中,我会使用装饰器。这样做的'R'tful方法是什么?说,我们有这种模式

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 )

我正在尝试使用format_inputformat_output 来包装对use_this_funcuse_this_other_func(和相关函数)的调用。部分使用这个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 decorator


【解决方案1】:

我认为你几乎在那里。这是一个示例,其中清洗的第一阶段是用 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) 返回一个“闭包”,这是一个带有封闭数据的函数。函数f 具有函数sqrt 的值作为该附件的一部分。

需要force 调用,因为在创建g 时不会评估f,并且在某些情况下,如果没有它,则在运行包装版本时将找不到f,因为R 的懒惰评价或“承诺”之类的。我从不完全确定何时会发生这种情况,但是将 force 调用添加到闭包生成器的未评估参数是零开销。它有点像货物狂热的编程,但从来都不是问题。

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

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)))。这是函数 compositionfunctional 包中有一个函数可以做到这一点:

> require(functional)
> w = Compose(format_input, sqrt, format_output)
> w(c(-2,2))
[1]        NA -1.414214

当您的组合中包含三个以上的函数时,这可能会更有用,例如,您可以有一个函数列表并使用 do.call.... 将它们组合在一起。

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

【讨论】:

  • +1 表示functional 包。非常感谢。在这里学到了一些东西。
猜你喜欢
  • 1970-01-01
  • 2018-02-02
  • 1970-01-01
  • 2022-06-28
  • 2021-07-25
  • 1970-01-01
  • 2019-01-14
  • 2017-03-19
  • 2018-12-14
相关资源
最近更新 更多