Question

I would like to add some functions f1,f2,...,fn so that I have a new function which yields f(x)=f1(x)+...+fn(x) (called pointwise addition). So I have a list of functions and tried

Reduce("funadd",fun.list)

where funadd is defined by

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

When testing funadd on two functions, it works flawlessly. However, when I try to evaluate the result of the Reduce command, I get the error

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

Solution

It's funny that Reduce does not work... Note that "reducing by hand" works:

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

Alternatively, you can use this:

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

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

EDIT: This is what is going on:

Looking at the source code for Reduce, we can see that it (roughly) has a loop doing this:

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

and continuing if there are more elements (init <- funadd(init, h), ...).

This causes the reference to f to be lost in the first loop iteration:

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

This happens because the f1 in the last retfun is pointing to itself:

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

As @Vincent figured it out, this can also be solved by forcing the arguments, i.e., by making a local copy that avoids lazy evaluation of f1 and f2:

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

OTHER TIPS

Forcing the evaluation of the arguments fixes the problem.

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
Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top