R装饰器更改输入和输出 [英] R decorator to change both input and output
问题描述
我正在尝试重构它。在Python中,我将使用装饰器。什么是最有效的方法?说,我们有这种模式
I am trying to refactor this. In Python, I would use a decorator. What's the 'R'tful way to do this? Say, we have this pattern
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 )
您可以想象,它像野蘑菇一样扩散。我想要接近解决方案的东西
As you can imagine, this proliferates like wild mushroom. I want something close to this solution
use_this_robust_func <- wrapper( use_this_func ) # Or wrapper( use_this_other_func )
good_output <- use_this_robust_func( bad_input )
我正在尝试将调用包装为 use_this_func
和 use_this_other_func
(及相关功能),以及 format_input
和 format_output
。到目前为止,我已经部分使用了问题
I'm trying to wrap the call to use_this_func
and use_this_other_func
(and related functions) with format_input
and format_output
. Using in part this question, so far I have
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。Rnative如何做到这一点?预先感谢。
Sorry for the pseudo-code. Note I am not sure that this is the way to go in R. I'm not wedded to the sketch of the solution above, which is born from translating Python - and badly at that - to R. How would a R native do this? Thanks in advance.
推荐答案
我认为您已经很多了。这是一个示例,其中清理的第一步是用NA替换负输入值,而输出清理很容易使所有内容取反:
I think you are pretty much there. Here's an example where the first stage of cleaning is to replace negative input values with NAs, and the output cleaning is simple to negate everything:
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
的值,作为该附件的一部分。
wrapper(sqrt)
returns a "closure", which is a function with enclosed data. The function f
has the value of the function sqrt
as part of that enclosure.
需要 force
调用,因为当<$ c $时未评估 f
c> g 已创建,并且在某些情况下,如果没有它,则由于R的惰性评估或在运行包装版本时找不到 f
承诺之类的。我不确定何时会发生这种情况,但是将 force
调用添加到闭包生成器的未求值参数是零开销。
The force
call is needed since f
doesn't get evaluated when g
is created, and in some cases without it then f
won't get found when running the wrapped version due to R's lazy evaluation or "promises" or something. I'm never exactly sure when this happens but adding a force
call to unevaluated arguments to closure generators is zero-overhead. Its a bit cargo-cult programming but never a problem.
更灵活的解决方案可能是将输入和输出清洗功能指定为闭合生成器的功能,默认情况下:
A more flexible solution might be to specify the input and output cleaning functions as functions to the closure generator, with defaults:
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
具有不同的输入和输出格式化程序。例如,将负函数更改为正数:
Then I can wrap sqrt
with different input and output formatters. For example to change that negative function with a positive one:
> 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)))
。这是函数 composition ,并且 functional
包中有一个函数可以做到这一点:
An even more flexible solution is to spot that you are generating chains of functions here. Your output is format_output(sqrt(format_output(bad_input)))
. This is function composition and there's a function in the functional
package to do that:
> require(functional)
> w = Compose(format_input, sqrt, format_output)
> w(c(-2,2))
[1] NA -1.414214
此也许当您的合成中包含三个以上的函数时,它会变得更加有用,例如,您可以拥有一个函数列表,并使用 do.call
将它们组合在一起。
This perhaps gets more useful when you have more than three functions in your composition, you could for example have a list of functions and compose them all together using do.call
....
一旦您看到函数式编程的模式会令人上瘾。我现在停止。
Once you see patterns in functional programming its addictive. I'll stop now.
这篇关于R装饰器更改输入和输出的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!