posure: Variable Composite Functions

posureR Documentation

Variable Composite Functions

Description

posure() enables you to create efficient variable (i.e., parameterized) composite functions.

For instance, say you have a composite function such as

  function(..., b = 2, n) {
    (sample %>>>% log(base = b) %>>>% rep(n))(...)
  }

  # Alternatively, expressed with the magrittr %>%:
  function(..., b = 2, n) {
    sample(...) %>% log(base = b) %>% rep(n)
  }

which varies according to the values of b and n. You can express this more succinctly with posure(), by dropping the placeholder argument (‘...’):

  posure(b = 2, n ~ {
    sample %>>>% log(base = b) %>>>% rep(n)
  })

This creates a function with same formals and return values.

But the posure() version is more efficient because it creates the composite function just once, rather than anew with each function call. Morever, it is robuster than the functionally equivalent construction with the magrittr `%>%` because posure() validates the constituent functions (see ‘Examples’).

Usage

posure(..., ..env = parent.frame())

Arguments

...

Function declaration whose body must be a function composition expressed using %>>>%. Quasiquotation is supported. The syntax is that of fn() (see ‘Function Declarations’) except that declaring ‘...’ among ... is ambiguous.

..env

Environment in which to create the function. (You should rarely need to set this.)

Details

posure() curries composite functions. However, the main significance of posure() is its efficiency, which is achieved via non-standard scoping semantics (transparent to the caller). posure() creates the given composite function once. When the resulting variable composite function is called, its dependencies are dynamically bound to its localized lexical scope, for fast lookup, then removed when the function exits. Thus a posure is a (parameterized) closure that is partially dynamically scoped. (This portmanteau is due to Henry Stanley.)

Value

Function with formals function (..., <composite_function_dependencies>), where <composite_function_dependencies> stands for the formals captured by the dots of posure(). In particular, a call of the form

  posure(a, b = value ~ f(a, b) %>>>% g(a, b))

produces a function with the same formals and return values as

  function(..., a, b = value) {
    (f(a, b) %>>>% g(a, b))(...)
  }

See Also

%>>>%, fn(), partial().

Examples

foo <- posure(b = 2, n ~ {
  sample %>>>% log(base = b) %>>>% rep(n)
})

# A posure is a composite function with dependencies:
foo

set.seed(1)
foo(2^(1:10), size = 2, n = 3)
#> [1] 3 4 3 4 3 4

set.seed(1)
rep(log(sample(2^(1:10), size = 2), base = 2), 3)
#> [1] 3 4 3 4 3 4

# However, a 'posure()' does the composition upfront, so it is faster
# than the equivalent function defined using the magrittr pipe:

library(magrittr)  # Provides the pipe %>%

foo_pipe <- function(..., b = 2, n) {
  sample(...) %>% log(base = b) %>% rep(n)
}

set.seed(1)
foo_pipe(2^(1:10), size = 2, n = 3)
#> [1] 3 4 3 4 3 4

# Moreover, posures are safer than functions defined using the pipe,
# because '%>>>%' validates constituent functions:
try(posure(b = 2, n ~ log(Base = b) %>>>% rep(n)))
# Error: unused argument (Base = b)

try(posure(b = 2 ~ my_sample %>>>% log(base = b)))
# Error: object 'my_sample' not found


gestalt documentation built on Aug. 22, 2022, 5:08 p.m.