output |
---|
html_document |
Generators are functions that behave like iterators, a type of object that contains a mutable internal state. When used correctly, they offer an efficient solution to many computational problems. This package provides a grammar for working with these tools.
This package was written to accompany a post on The Big Blog of R Adventures. It provides much more detail on how design and implementation of this project.
Iterators typically contain a next method to create new values of the internal state. Generators accomplish this through successive function calls. In R, we can implement this tool using closures. The simplest of these is the counter. Using an example from Hadley Wickham, we can implement a simple count generator as follows,
counter <- function() {
i <- 0
function() {
i <<- i + 1
i
}
}
This is what it looks like in action.
my_counter <- counter()
my_counter()
#> 1
my_counter()
#> 2
This simple function has a very useful structure that can built upon to create a much more general tool:
- At the heart of it all, we have a mutable state:
i
. - We modify it with the scoping assignment operator
<<-
. - Subsequent calls to the function update the state.
- And each call returns (a version of) the changed state.
Together, these components form the arguments of the function generator
.
.state
is a vector. It doesn't necessarily have to be a scalar.update
controls how that state changes over time.yield
governs how values from the state are returned to form the series
A wide variety of iterators can be constructed using these three arguments, but many users might want to use other tools to create new generators. For these purposes, the following are provided:
copy
create a new generator whose state does not affect the originalkeep
ordiscard
controls which elements of the series are shownwrap
changes the series output, whilerebase
changes the update functionskip
moves the series forward a specific number of stepstake
transforms a set number of values into a list or vectorreset
sends it back to its startlimit
provides an end to the series (when the series is exhausted)recycle
resets the generator when it is exhaustedconsume
generates the series until its limitsfoldn
andfoldc
reduces the series to a single value, using a binary function
Generators are a common type of object in many programming languages, and this package draws heavily from concepts impelemented in Javascript and Python. Reginald Braithwaite's book, Javascript Allonge, has an excellent introduction to generators in that language, and I learned about their implementation in Python thanks to [Jeff Knupp's blog](https://jeffknupp.com/blog/2013/04/07/improve- your-python-yield-and-generators-explained/).
An iterator syntax is provided in Rust. It is described well in Rust's documentation and its accompanying book. These concepts informed the generator grammar described in this package.
Iterators already exist in R, through the iterators
and
itertools
packages, but the implementations and design goals are different. This package
is obviously indebted to Rich Calaway, Steve Weston and Hadley Wickham for
their work, and I am incredibly grateful to be able to reference it.
To install the development version of this package:
# install.packages("devtools")
devtools::install_github("michaelquinn32/generators")