๐ŸŽ“ A1Learner
๐Ÿ”
0 of 27 lessons completed

R Function Factories

A function factory is a function that builds and returns new functions. This factory returns a list of closures that share one state environment.

Add and read share one box

make_keeper() builds one state environment and returns a list of closures. add() grows the stored total and read() reports the same total.

make_keeper <- function() {
  state <- new.env()
  state$total <- 0
  add <- function(amount) {
    state$total <- state$total + amount
    state$total
  }
  read <- function() {
    state$total
  }
  reset <- function() {
    state$total <- 0
    state$total
  }
  list(add = add, read = read, reset = reset)
}
keeper <- make_keeper()
print(keeper$add(10))
print(keeper$add(5))
print(keeper$read())

Reset clears the shared total

reset() writes zero into the same state environment. The next read() shows zero, and a later add() starts again from there.

make_keeper <- function() {
  state <- new.env()
  state$total <- 0
  add <- function(amount) {
    state$total <- state$total + amount
    state$total
  }
  read <- function() {
    state$total
  }
  reset <- function() {
    state$total <- 0
    state$total
  }
  list(add = add, read = read, reset = reset)
}
keeper <- make_keeper()
print(keeper$add(20))
print(keeper$add(8))
print(keeper$reset())
print(keeper$read())
print(keeper$add(3))

Two keepers stay independent

first and second come from two calls to the same factory. Each call built its own environment, so the totals grow apart.

make_keeper <- function() {
  state <- new.env()
  state$total <- 0
  add <- function(amount) {
    state$total <- state$total + amount
    state$total
  }
  read <- function() {
    state$total
  }
  reset <- function() {
    state$total <- 0
    state$total
  }
  list(add = add, read = read, reset = reset)
}
first <- make_keeper()
second <- make_keeper()
print(first$add(10))
print(first$add(10))
print(second$add(7))
print(first$read())
print(second$read())

Example

make_keeper <- function() {
  state <- new.env()
  state$total <- 0
  add <- function(amount) {
    state$total <- state$total + amount
    state$total
  }
  read <- function() {
    state$total
  }
  reset <- function() {
    state$total <- 0
    state$total
  }
  list(add = add, read = read, reset = reset)
}
team <- make_keeper()
solo <- make_keeper()
print(team$add(12))
print(team$add(6))
print(solo$add(30))
print(team$reset())
print(team$read())
print(solo$read())

Key points

  • A factory call builds a fresh state environment with new.env().
  • The factory returns a list of functions that all read and write that one environment.
  • Each function in the list is a closure over the shared state.
  • add, read and reset change or report the same stored total.
  • Two keepers built by two factory calls hold separate environments.
  • Separate environments keep the two totals fully independent.

In this example, team and solo are two keepers from one factory. Resetting team clears only its own total, and solo still reads 30 at the end.

Note

The state lives in an environment, so the closures need no special assignment arrow.

Try it Yourself

Edit the code, then press Run.

Running is simulated ยท rdrr.io R Snippets

Exercise

A keeper is built and add(10) then add(5) run on it. What does read() print?