R Closures
A factory is a function that builds and returns a new function. The returned function is a closure, because it carries the factory's state with it.
A counter that remembers
make_counter builds a state environment and returns a function. Each call to visits adds one to state$n, and the counts climb because the state survives between calls.
make_counter <- function() {
state <- new.env()
state$n <- 0
function() {
state$n <- state$n + 1
state$n
}
}
visits <- make_counter()
print(visits())
print(visits())Two counters count on their own
red and blue come from the same factory. Each one holds a separate state environment, so blue starts at one while red is already at two.
make_counter <- function() {
state <- new.env()
state$n <- 0
function() {
state$n <- state$n + 1
state$n
}
}
red <- make_counter()
blue <- make_counter()
print(red())
print(red())
print(blue())The factory argument sets the step
make_stepper takes a step size when the factory runs. by_five adds five on every call because step lives with the state.
make_stepper <- function(step) {
state <- new.env()
state$n <- 0
function() {
state$n <- state$n + step
state$n
}
}
by_five <- make_stepper(5)
print(by_five())
print(by_five())
print(by_five())Example
make_pot <- function(label) {
state <- new.env()
state$total <- 0
function(amount) {
state$total <- state$total + amount
cat(label, "holds", state$total, "\n")
}
}
rent <- make_pot("Rent")
food <- make_pot("Food")
rent(300)
rent(150)
food(80)Key points
- A factory runs once and returns a function.
- Each call to the factory builds a fresh state environment with new.env().
- The returned function reads and changes its own state through state$n.
- An ordinary local variable would vanish when a call ends, but the state environment stays alive between calls.
- Two functions from one factory hold separate state and count on their own.
In this example make_pot builds a saving pot with its own state environment. rent and food add to separate totals, and each line prints the pot label with its running total.
Note
the state lives in an environment, so the returned function needs no special assignment arrow to change it.
Try it Yourself
Edit the code, then press Run.
Running is simulated ยท rdrr.io R Snippets
Exercise
A counter factory is called twice, making counters a and b. After a() runs twice, what does the first call to b() print?