A tower is equivalent to the Ruby gem Rack's notion of middleware.

tower(functions = list())

Arguments

functions

list. A list of functions in the tower. The first argument of each function must be named "object" and each function must take a ... parameter. By default list(), which creates an identity tower that performs no operation.

Value

An S3 "tower" object, which is a callable function and must be passed the object as the first argument. Additional arguments will be passed to the first function in the tower.

Details

Imagine a function f1 that, in the middle of its processing, calls another function, f2, which in the middle of its processing, calls another function, f3, and so on.

To construct such a structure from the list of functions list(f1, f2, ...) we need to be able to call the next "inner" function from the previous outer function.

This is accomplished by providing a yield keyword which simply calls the next function in the tower.

The purpose of a tower is to modify some primary object throughout its operation. To this end, an object keyword will be provided to each tower function. If object is modified prior to a yield call, the next function in the tower will receive the modified object.

For composability, every function in a tower should have a yield keyword. The last function in the tower will yield to an identity function that simply returns the object.

Examples

functions <- list( function(object, ...) { object <- object + 1 object <- yield() object + 1 }, function(object, ...) { object <- object * 2 yield() } ) t <- tower(functions) v <- t(1) # This is now 5, since in the tower, we increment object, # Multiply it by 2 in the next function, then increment it # again after receiving the previous function. stopifnot(v == 5)