R / CHAPTER 11

Lexical scope and forced configuration

Advanced

Keep function factories predictable when arguments are lazy.

By the end of this chapter

  • Trace lexical lookup
  • Recognize deferred argument evaluation
  • Force configuration captured by a closure

The idea

An R function carries its enclosing environment, so a returned function can keep access to local configuration after its factory finishes. Name lookup follows lexical scope rather than the environment of whichever caller happens to invoke the function later. Separate factory calls can create separate environments, which supports small configurable transformations without global variables.

Function arguments are promises evaluated when needed. A factory that captures an argument without evaluating it may observe a changed referenced variable when the returned function eventually forces that promise. Use force inside the factory when configuration should be fixed at creation time. Document whether state is a snapshot or a live dependency, and avoid superassignment when ordinary return values can express the update more clearly.

R example
make_adder <- function(offset) {
  force(offset)
  function(x) x + offset
}
n <- 3
add <- make_adder(n)
n <- 9
cat(add(2), "\n", sep="")
Result
5

Forcing offset captures its evaluated value before n is reassigned. The returned function uses the factory’s environment.

Try it yourself

Build a threshold predicate factory that snapshots its threshold.

Use your own editor for this exercise. Runnable challenges on CodeQuest are available for JavaScript, Python, and SQL.

CHECK YOUR UNDERSTANDING

Chapter checkpoint

A closure should retain the configuration supplied when its factory was called. Which step establishes that evaluation time?