如何使用Reduce从函数列表中创建新函数?

时间:2013-09-11 12:21:15

标签: r reduce

我想添加一些函数f1,f2,...,fn,这样我就有了一个新函数,它产生f(x)= f1(x)+ ... + fn(x)(称为逐点加法) )。所以我有一个功能列表并尝试了

Reduce("funadd",fun.list)

其中funadd由

定义
funadd <- function(f1,f2){
    retfun <- function(x){
        f1(x)+f2(x)
    }
    retfun
}

在两个函数上测试funadd时,它可以完美运行。但是,当我尝试评估Reduce命令的结果时,我收到错误

Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

2 个答案:

答案 0 :(得分:5)

Reduce不起作用很有趣......请注意“手工减少”有效:

f <- function(x) x^2
g <- function(x) x^3
h <- function(x) x^4
x <- runif(3)

f(x)+g(x)+h(x)
#[1] 0.9760703 0.1873004 0.1266966

funadd(funadd(f,g),h)(x)
#[1] 0.9760703 0.1873004 0.1266966

或者,你可以使用它:

funadd2 <- function(...){
    function(x) Reduce(`+`, lapply(list(...), function(f) f(x)))
}

funadd2(f,g,h)(x)
#[1] 0.9760703 0.1873004 0.1266966

编辑:这是正在发生的事情:

查看Reduce的源代码,我们可以看到它(大致)有一个循环这样做:

init <- f
init <- funadd(init, g)

并继续,如果有更多元素(init <- funadd(init, h),...)。

这会导致f的引用在第一次循环迭代中丢失:

init(x)
# Error: evaluation nested too deeply: infinite recursion / options(expressions=)?

这是因为最后f1中的retfun指向了自己:

identical(environment(init)$f1, init, ignore.environment=FALSE)
# [1] TRUE

正如@Vincent所知,这也可以通过强制参数来解决,即通过制作避免对f1f2进行惰性评估的本地副本:

funadd3 <- function(f1,f2){
    f1.save <- f1
    f2.save <- f2
    retfun <- function(x){
        f1.save(x)+f2.save(x)
    }
    retfun
}

Reduce(funadd3, list(f,g,h))(x)
# [1] 0.9760703 0.1873004 0.1266966

答案 1 :(得分:5)

强制评估参数可以解决问题。

funadd <- function(f1,f2){
    force(f1)
    force(f2)
    retfun <- function(x){
        f1(x)+f2(x)
    }
    retfun
}
r <- Reduce( funadd, list( f, g, h ) )
r(x)  # works