R装饰器更改输入和输出 [英] R decorator to change both input and output

查看:67
本文介绍了R装饰器更改输入和输出的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我正在尝试重构它。在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屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆