R / CHAPTER 11
Lexical scope and forced configuration
AdvancedKeep 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.
make_adder <- function(offset) {
force(offset)
function(x) x + offset
}
n <- 3
add <- make_adder(n)
n <- 9
cat(add(2), "\n", sep="")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