wrapr includes de-referencing, function evaluation, and a new concept called "wrapr_applicable". "wrapr_applicable" is dispatch by type of right hand side argument scheme.

Basic wrapr

The wrapr pipe operators (%.>% and %>.%) are roughly defined as: a %>.% b ~ { . <- a; b };. This works under the assumption that b is an expression with free-instances of “.”. A typical use is:

library("wrapr")

5 %.>% sin(.)
#> [1] -0.9589243

The above is performed by standard S3 dispatch on the left argument of an exported generic function called pipe_step(). A formal description of wrapr piping can be found here.

Dereferencing and function evaluation

wrapr works primarily over expressions and “.”. wrapr does tries to de-reference names found in the right-hand side of pipe stages, and also dispatches functions. One can also write the following.

5 %.>% sin
#> [1] -0.9589243
5 %.>% base::sin # new for wrapr 1.3.1
#> [1] -0.9589243

"wrapr_applicable"

Arbitrary objects ask wrapr to treat them as special expressions by:

  1. Adding the string "wrapr_applicable" to their class declarations.
  2. Implement an S3 generic "wrapr_function" with a function of signature (pipe_left_arg, pipe_right_arg, , pipe_environment). Note S3 dispatch is on the right argument.

If these two conditions are met then wrapr instead of evaluating the object calls the function wrapr_function.

For example:

function_reference <- list(f = sin)
class(function_reference) <- c("wrapr_applicable", "ourclass")

#' Wrapr function.
#'
#' S3 dispatch on tyhpe of pipe_right_argument.
#'
#' @param pipe_left_arg left argument.
#' @param pipe_right_arg right argument.
#' @param pipe_environment environment to evaluate in.
#' @param pipe_name character, name of pipe operator.
#' @return result
#'
#' @export
#'
wrapr_function.ourclass <- function(pipe_left_arg, 
                                    pipe_right_arg,
                                    pipe_environment,
                                    pipe_name) {
  pipe_right_arg$f(pipe_left_arg)
}

function_reference
#> $f
#> function (x)  .Primitive("sin")
#> 
#> attr(,"class")
#> [1] "wrapr_applicable" "ourclass"

5 %.>% function_reference
#> [1] -0.9589243

function_reference$f <- sqrt
5 %.>% function_reference
#> [1] 2.236068

The signature arguments work as follows:

  • pipe_left_arg: The value moving down the pipeline.
  • pipe_right_arg: The right pipeline operator (essentially “self” or “this” in object oriented terms, used for S3 dispatch).
  • pipe_environment: The environment the pipeline is working in (not usually needed).
  • `pipe_name: The name of the pipe operator (not usually needed).

This functionality allows arbitrary objects to directly specify their intended pipeline behavior.

Let’s use a debugging function to see the values of all of the arguments.

wrapr_function.ourclass <- function(pipe_left_arg, 
                                    pipe_right_arg,
                                    pipe_environment,
                                    pipe_name) {
  print("pipe_left_arg")
  print(pipe_left_arg)
  print("pipe_right_arg")
  print(pipe_right_arg)
  print("pipe_environment")
  print(pipe_environment)
  print("pipe_name")
  print(pipe_name)
  pipe_right_arg$f(pipe_left_arg)
}

5 %.>% function_reference
#> [1] "pipe_left_arg"
#> [1] 5
#> [1] "pipe_right_arg"
#> $f
#> function (x)  .Primitive("sqrt")
#> 
#> attr(,"class")
#> [1] "wrapr_applicable" "ourclass"        
#> [1] "pipe_environment"
#> <environment: R_GlobalEnv>
#> [1] "pipe_name"
#> [1] "%.>%"
#> [1] 2.236068

Conclusion

wrapr values (left-hand sides of pipe expressions) are completely general. wrapr operators (right-hand sides of pipe expressions) are primarily intended to be expressions that have “.” as a free-reference. wrapr can also be used with right-hand sides that are function references or with arbitrary annotated objects.