Piotr Wilczek
Piotr Wilczek

Reputation: 197

A function within a function in the R language

I have a simple function in the R language, for instance:

f<-function(x){
y=(x+2)/3
return(y)
}

I want to evaluate this function five times on its own outputs, i.e., y1=f(x), y2=f(f(x)), y3=f(f(f(x))), y4=f(f(f(f(x)))), y5=f(f(f(f(f(x))))). Is there a simpler way to do it in the form of one function, for instance the function with two arguments when the first argument is x and the second argument is the number of evaluation times, i.e., n. For instance, for x=3 and n=5 I would like to have the function f2<-(x=3,n=5) whose output would be in the form of a vector or a list of the length equal to n with the values:

y1=f(3)=1.666667
y2=f(f(3))=1.222222
y3=f(f(f(3)))=1.074074
y4=f(f(f(f(3))))=1.024691
y5=f(f(f(f(f(3)))))=1.00823

How to write such one function in the R ?

Upvotes: 3

Views: 133

Answers (4)

IceCreamToucan
IceCreamToucan

Reputation: 28685

Reduce will do this if you add a "junk" argument to your f. If you just want the last result set accumulate = F or just remove the accumulate argument from the function

f<-function(x, junk){
y=(x+2)/3
return(y)
}

Reduce(f, x = numeric(5), init = 3, accumulate = T)
# [1] 3.000000 1.666667 1.222222 1.074074 1.024691 1.008230

Or with purrr

purrr::accumulate(numeric(5), f, .init = 3)
# [1] 3.000000 1.666667 1.222222 1.074074 1.024691 1.008230

Upvotes: 1

Rui Barradas
Rui Barradas

Reputation: 76402

Using the accepted answer in another post, just use Reduce to create the composition, g.

composite <- function(g, h) {function(...)g(h(...))}
g <- Reduce(composite, list(f, f, f, f, f))

g(2)
f(f(f(f(f(2)))))

identical(g(2), f(f(f(f(f(2))))))
#[1] TRUE

Upvotes: 4

M--
M--

Reputation: 28825

You can also tweak your original function like below:

f2<-function(x, steps){
             ans<-c(x)
              for (i in 1:steps) {
                   y=(x+2)/3
                   ans=append(ans,y)
                   x = y
  }
    return(ans)
}

f2(3,5)
#> [1] 3.000000 1.666667 1.222222 1.074074 1.024691 1.008230

Upvotes: 2

John Coleman
John Coleman

Reputation: 51998

You can write a helper function like:

iterate <- function(f,s,n){
  iterates <- vector(length = n+1)
  iterates[1] <- s
  for(i in 1:n){
    iterates[i+1] <- f(iterates[i])
  }
  iterates
}

Then, for example,

> iterate(function(x){(x+2)/3},3,5)
[1] 3.000000 1.666667 1.222222 1.074074 1.024691 1.008230

You can of course modify the above code so that the vector would start with f(s) rather than s.

Upvotes: 3

Related Questions