wrapr Eager Evaluation

John Mount, Win-Vector LLC

2023-08-19

wrapr dot arrow piping is designed to emphasize a a %.>% b “is nearly” {. <- a; b} semantics. In many cases this makes a piped expression of the form a %.>% b(.) look very much like b(a). This leads to the observation that “wrapr explicit dot notation” appears to need one more dot than the common “magrittr dot is a new implicit first argument notation.”

There are some special rules around things like names. For example 5 %.>% sin is not valued as sin, which would be the strict interpretation of {. <- 5; sin}. Instead it is expanded to something closer {. <- 5; sin(.)}, which intentionally looks very much like sin(5). In more complicated cases the user can signal they wish for an eager evaluation of this style by writing on outer .() container.

And wrapr now also exposes an “eager” annotation such that function evaluations or array indexing operations so-annotated are interpreted as a %.>% f(...) is interpreted roughly as {. <- a; _f <- eval(f(...)); _f(.)}, where _f is a notional temporary variable (not visible or produces as a side-effect). This effect is used in wrapr’s “pipe to array” variation of the unpack notation (example here).

This eager effect can be gotten by setting the appropriate attribute as we see below.

For array notation:

library(wrapr)
lst <- list(sin)

# without the attribute, the function is returned
4 %.>% lst[[1]]
#> function (x)  .Primitive("sin")
# an outer .() signals for eager eval from the pipeline
4 %.>% .(lst[[1]])
#> [1] -0.7568025
# with the attribute, the array is always de-referenced
# before the pipe execution allowing the function
# to be evaluated using the piped-in value.
attr(lst, 'dotpipe_eager_eval_bracket') <- TRUE

4 %.>% lst[[1]]
#> [1] -0.7568025

For functions:

# without the attribute the result is sin
f <- function(...) { sin }
4 %.>% f()
#> function (x)  .Primitive("sin")
# an outer .() signals for eager eval from the pipeline
4 %.>% .(f())
#> [1] -0.7568025
# with the attribute the result is sin(4)
attr(f, 'dotpipe_eager_eval_function') <- TRUE

4 %.>% f()
#> [1] -0.7568025

Essentially objects with this attribute have an implicit .() “eager eval” on them.