2012-08-06 281 views
4

我有一种情况,我想通过Compose链接的函数传递参数。我意识到我可以在参数中使用库里,但是我希望得到的函数比这更灵活。这里有一个简单的测试用例来说明问题:将参数传递给Compose的函数?

> library(functional) 
> f <- function(x, scale) x^2*scale 
> g <- function(y, shift) sqrt(y)+shift 
> h <- Compose(f,g) 
> h(1) 
Error in x^2 * scale : 'scale' is missing 
> h(1, scale=1, shift=0) 
Error in Reduce(function(x, f) f(x), fs, ...) : 
    unused argument(s) (scale = 1, shift = 0) 

有没有办法使用Compose使得它允许产生的功能仍然允许参数被调用时? ?Compose不是很有帮助,除了可能作为一个可爱的键盘elegy。

+0

您从哪些包获得撰写? – Dason 2012-08-06 13:53:36

+0

安德烈 - 苛刻! @Dason这是(现在,感谢乔希的编辑)我的代码中的第一行:-)。对不起,忘了复制/粘贴该行。 – 2012-08-06 13:58:06

回答

6

由于function composition是在计算机科学中制定的,所有的功能都只有一个参数。 Composition函数也假设这一点。这是一个典型的解决方案。另一个复杂因素是任何其他命名参数都必须传递给组合过程中的正确函数。

这里有几个办法:

h1 <- function(scale, shift) 
    Compose(Curry(f,scale), Curry(g,shift)) 

h1采取命名参数,并创建与那些在正确的令行禁止组成的功能。返回是1参数功能:

> h1(scale=1, shift=0)(1) 
[1] 1 

另一种方法是延迟压缩(并因此延迟)直到实际功能评估。在这种情况下,原始的“撰写”功能只是设置一切,但实际上并不构成,返回一个函数,该函数可以进行粘贴,合成和评估。

ComposeDelayedCurry <- function(...) { 
    fs <- list(...) 
    all.formals <- lapply(fs, formals) 
    function(...) { 
    local.args <- list(...) 
    pos.args <- lapply(all.formals, function(f) { 
     local.args[names(f)[[-1]]] 
    }) 
    curried <- lapply(seq_along(fs), function(i) { 
     do.call(Curry, c(fs[[i]], pos.args[[i]])) 
    }) 
    do.call(Compose, curried)(..1) 
    } 
} 

h2 <- ComposeDelayedCurry(f,g) 

现在呼吁h2将在评估时做所有的工作。这做了几个假设。一个是每个函数(和函数调用)的第一个参数是正在编写的函数。第二个是所有其他参数都是命名参数。没有任何东西可以通过...传递给函数。这是因为必须检查每个函数的形式,以便知道每个参数“去”的位置。我认为这将处理不指定具有默认值的参数,但我不完全确定。

> h2(1, scale=1, shift=0) 
[1] 1 
> h2(3, scale=5, shift=2) 
[1] 8.708204 
> sqrt(5*(3^2))+2 
[1] 8.708204