Learn R Programming

⚠️There's a newer version (2.1.0) of this package.Take me there.

wrapr is an R package that supplies powerful tools for writing and debugging R code.

Introduction

Primary wrapr services include:

library(wrapr)
packageVersion("wrapr")
 #  [1] '1.9.6'
date()
 #  [1] "Wed Jan 22 18:20:54 2020"

%.>% (dot pipe or dot arrow)

%.>% dot arrow pipe is a pipe with intended semantics:

a %.>% b” is to be treated approximately as if the user had written “{ . <- a; b };” with “%.>%” being treated as left-associative.

Other R pipes include magrittr and pipeR.

The following two expressions should be equivalent:

cos(exp(sin(4)))
 #  [1] 0.8919465

4 %.>% sin(.) %.>% exp(.) %.>% cos(.)
 #  [1] 0.8919465

The notation is quite powerful as it treats pipe stages as expression parameterized over the variable “.”. This means you do not need to introduce functions to express stages. The following is a valid dot-pipe:

1:4 %.>% .^2 
 #  [1]  1  4  9 16

The notation is also very regular as we show below.

1:4 %.>% sin
 #  [1]  0.8414710  0.9092974  0.1411200 -0.7568025
1:4 %.>% sin(.)
 #  [1]  0.8414710  0.9092974  0.1411200 -0.7568025
1:4 %.>% base::sin
 #  [1]  0.8414710  0.9092974  0.1411200 -0.7568025
1:4 %.>% base::sin(.)
 #  [1]  0.8414710  0.9092974  0.1411200 -0.7568025

1:4 %.>% function(x) { x + 1 }
 #  [1] 2 3 4 5
1:4 %.>% (function(x) { x + 1 })
 #  [1] 2 3 4 5

1:4 %.>% { .^2 } 
 #  [1]  1  4  9 16
1:4 %.>% ( .^2 )
 #  [1]  1  4  9 16

Regularity can be a big advantage in teaching and comprehension. Please see “In Praise of Syntactic Sugar” for more details. Some formal documentation can be found here.

Some obvious “dot-free”" right-hand sides are rejected. Pipelines are meant to move values through a sequence of transforms, and not just for side-effects. Example: 5 %.>% 6 deliberately stops as 6 is a right-hand side that obviously does not use its incoming value. This check is only applied to values, not functions on the right-hand side.

Trying to pipe into a an “zero argument function evaluation expression” such as sin() is prohibited as it looks too much like the user declaring sin() takes no arguments. One must pipe into either a function, function name, or an non-trivial expression (such as sin(.)). A useful error message is returned to the user: wrapr::pipe does not allow direct piping into a no-argument function call expression (such as "sin()" please use sin(.)).

Some reserved words can not be piped into. One example is 5 %.>% return(.) is prohibited as the obvious pipe implementation would not actually escape from user functions as users may intend.

Obvious de-references (such as $, ::, @, and a few more) on the right-hand side are treated performed (example: 5 %.>% base::sin(.)).

Outer parenthesis on the right-hand side are removed (example: 5 %.>% (sin(.))).

Anonymous function constructions are evaluated so the function can be applied (example: 5 %.>% function(x) {x+1} returns 6, just as 5 %.>% (function(x) {x+1})(.) does).

Checks and transforms are not performed on items inside braces (example: 5 %.>% { function(x) {x+1} } returns function(x) {x+1}, not 6).

The dot arrow pipe has S3/S4 dispatch (please see ). However as the right-hand side of the pipe is normally held unevaluated, we don’t know the type except in special cases (such as the rigth-hand side being referred to by a name or variable). To force the evaluation of a pipe term, simply wrap it in .().

The dot pipe is also user configurable through standard S3/S4 methods.

The dot pipe has been formally written up in the R Journal.

@article{RJ-2018-042,
  author = {John Mount and Nina Zumel},
  title = {{Dot-Pipe: an S3 Extensible Pipe for R}},
  year = {2018},
  journal = {{The R Journal}},
  url = {https://journal.r-project.org/archive/2018/RJ-2018-042/index.html}
}

unpack/to multiple assignments

Unpack a named list into the current environment by name (for a positional based multiple assignment operator please see zeallot, for another named base multiple assigment please see vadr::bind).

d <- data.frame(
  x = 1:9,
  group = c('train', 'calibrate', 'test'),
  stringsAsFactors = FALSE)

to[
  train_data <- train,
  calibrate_data <- calibrate,
  test_data <- test
  ] <- split(d, d$group)

knitr::kable(train_data)
xgroup
11train
44train
77train

as_named_list

Build up named lists. Very convenient for managing workspaces when used with used with unpack/to.

as_named_list(train_data, calibrate_data, test_data)
 #  $train_data
 #    x group
 #  1 1 train
 #  4 4 train
 #  7 7 train
 #  
 #  $calibrate_data
 #    x     group
 #  2 2 calibrate
 #  5 5 calibrate
 #  8 8 calibrate
 #  
 #  $test_data
 #    x group
 #  3 3  test
 #  6 6  test
 #  9 9  test

build_frame() / draw_frame()

build_frame() is a convenient way to type in a small example data.frame in natural row order. This can be very legible and saves having to perform a transpose in one’s head. draw_frame() is the complimentary function that formats a given data.frame (and is a great way to produce neatened examples).

x <- build_frame(
   "measure"                   , "training", "validation" |
   "minus binary cross entropy", 5         , -7           |
   "accuracy"                  , 0.8       , 0.6          )
print(x)
 #                       measure training validation
 #  1 minus binary cross entropy      5.0       -7.0
 #  2                   accuracy      0.8        0.6
str(x)
 #  'data.frame':   2 obs. of  3 variables:
 #   $ measure   : chr  "minus binary cross entropy" "accuracy"
 #   $ training  : num  5 0.8
 #   $ validation: num  -7 0.6
cat(draw_frame(x))
 #  x <- wrapr::build_frame(
 #     "measure"                     , "training", "validation" |
 #       "minus binary cross entropy", 5         , -7           |
 #       "accuracy"                  , 0.8       , 0.6          )

qc() (quoting concatenate)

qc() is a quoting variation on R’s concatenate operator c(). This code such as the following:

qc(a = x, b = y)
 #    a   b 
 #  "x" "y"

qc(one, two, three)
 #  [1] "one"   "two"   "three"

qc() also allows bquote() driven .()-style argument escaping.

aname <- "I_am_a"
yvalue <- "six"

qc(.(aname) := x, b = .(yvalue))
 #  I_am_a      b 
 #     "x"  "six"

Notice the := notation is required for syntacitic reasons.

:= (named map builder)

:= is the “named map builder”. It allows code such as the following:

'a' := 'x'
 #    a 
 #  "x"

The important property of named map builder is it accepts values on the left-hand side allowing the following:

name <- 'variableNameFromElsewhere'
name := 'newBinding'
 #  variableNameFromElsewhere 
 #               "newBinding"

A nice property is := commutes (in the sense of algebra or category theory) with R’s concatenation function c(). That is the following two statements are equivalent:

c('a', 'b') := c('x', 'y')
 #    a   b 
 #  "x" "y"

c('a' := 'x', 'b' := 'y')
 #    a   b 
 #  "x" "y"

The named map builder is designed to synergize with seplyr.

%?% (coalesce)

The coalesce operator tries to replace elements of its first argument with elements from its second argument. In particular %?% replaces NULL vectors and NULL/NA entries of vectors and lists.

Example:

c(1, NA) %?% list(NA, 20)
 #  [1]  1 20

%.|% (reduce/expand args)

The operators %.|% and %|.% are wrappers for do.call(). These functions are used to pass arguments from a list to variadic function (such as sum()). The operator symbols are meant to invoke non-tilted versions of APL’s reduce and expand operators.

1:10 %.|% sum
 #  [1] 55

1:4 %.>% do.call(log, list(., base = 2))
 #  [1] 0.000000 1.000000 1.584963 2.000000

DebugFnW()

DebugFnW() wraps a function for debugging. If the function throws an exception the execution context (function arguments, function name, and more) is captured and stored for the user. The function call can then be reconstituted, inspected and even re-run with a step-debugger. Please see our free debugging video series and vignette('DebugFnW', package='wrapr') for examples.

λ() (anonymous function builder)

λ() is a concise abstract function creator or “lambda abstraction”. It is a placeholder that allows the use of the -character for very concise function abstraction.

Example:

# Make sure lambda function builder is in our enironment.
wrapr::defineLambda()

# square numbers 1 through 4
sapply(1:4, λ(x, x^2))
 #  [1]  1  4  9 16

# alternate "colon equals with braces" function builder notation
sapply(1:4, x := { x^2 })
 #  [1]  1  4  9 16

let()

let() allows execution of arbitrary code with substituted variable names (note this is subtly different than binding values for names as with base::substitute() or base::with()).

The function is simple and powerful. It treats strings as variable names and re-writes expressions as if you had used the denoted variables. For example the following block of code is equivalent to having written “a + a”.

a <- 7

let(
  c(VAR = 'a'),
  
  VAR + VAR
)
 #  [1] 14

This is useful in re-adapting non-standard evaluation interfaces (NSE interfaces) so one can script or program over them.

We are trying to make let() self teaching and self documenting (to the extent that makes sense). For example try the arguments “eval=FALSE” prevent execution and see what would have been executed, or debug=TRUE to have the replaced code printed in addition to being executed:

let(
  c(VAR = 'a'),
  eval = FALSE,
  {
    VAR + VAR
  }
)
 #  {
 #      a + a
 #  }

let(
  c(VAR = 'a'),
  debugPrint = TRUE,
  {
    VAR + VAR
  }
)
 #  $VAR
 #  [1] "a"
 #  
 #  {
 #      a + a
 #  }
 #  [1] 14

Please see vignette('let', package='wrapr') for more examples. Some formal documentation can be found here. wrapr::let() was inspired by gtools::strmacro() and base::bquote(), please see here for some notes on macro methods in R.

For working with dplyr 0.7.* we strongly suggest wrapr::let() (or even an alternate approach called seplyr).

Installation

Install with:

install.packages("wrapr")

More Information

More details on wrapr capabilities can be found in the following two technical articles:

Note

Note: wrapr is meant only for “tame names”, that is: variables and column names that are also valid simple (without quotes) R variables names.

Copy Link

Version

Install

install.packages('wrapr')

Monthly Downloads

3,403

Version

1.9.6

License

GPL-2 | GPL-3

Issues

Pull Requests

Stars

Forks

Maintainer

John Mount

Last Published

January 26th, 2020

Functions in wrapr (1.9.6)

DebugFnW

Wrap a function for debugging.
DebugFn

Capture arguments of exception throwing function call for later debugging.
PartialNamedFn-class

Package qualified name of a function as a function.
DebugPrintFn

Capture arguments of exception throwing function call for later debugging.
DebugFnWE

Wrap function to capture arguments and environment of exception throwing function call for later debugging.
DebugFnE

Capture arguments and environment of exception throwing function call for later debugging.
PartialFunction-class

Function with partial arguments as a new single argument function.
ApplyTo

Apply a single argument function to its argument.
DebugPrintFnE

Capture arguments and environment of exception throwing function call for later debugging.
UnpackerP

Create a value unpacking object (eager pipe version).
SrcFunction-class

Code text as a new partial function.
apply_right.default

Default apply_right implementation.
apply_right.UnaryFn

Apply right wrapped function to argument on left.
UnaryFn-class

Functions that take a single argument
apply_right_S4

S4 dispatch method for apply_right.
apply_left.Collector

Capture all right-arguments unevaluated.
apply_right.locum

S3 dispatch on class of pipe_right_argument for a locum.
add_name_column

Add list name as a column to a list of data.frames.
bquote_call

Treat ... call argument as bquoted-values.
UnaryFnList-class

List of Unary functions taken in order.
as_dot_fn

Convert an unevaluted pipeline into a function.
UnpackerF

Create a value unpacking object (function version).
build_frame

Build a data.frame from the user's description.
bquote_call_args

Treat ... argument as bquoted-values.
c.UnaryFn

Combine UnaryFns
as.character.locum

Format a locum for presentation.
buildNameCallback

Build a custom writeback function that writes state into a user named variable.
concat_items_rev

build a list of all UnaryFn from possibly composite
bquote_function

Adapt a function to use bquote on its arguments.
as.UnaryFn

Convert a list of UnaryFns into a UnaryFn.
coalesce

Coalesce values (NULL/NA on left replaced by values on the right).
format.PartialNamedFn

format step
%c%

Inline list/array concatenate.
format.PartialFunction

format step
%dot%

Inline dot product.
Collector

Build a collector that can capture all pipe stages to the right.
apply_left

S3 dispatch on class of pipe_left_arg.
VectorizeM

Memoizing wrapper to base::Vectorize()
draw_frame

Render a simple data.frame in build_frame format.
checkColsFormUniqueKeys

Check that a set of columns form unique keys.
execute_parallel

Execute f in parallel partitioned by partition_column.
as_fn

Convert a pipeable object into a function.
check_equiv_frames

Check two data.frames are equivilent after sorting columns and rows.
fnlist

Wrap a list of functions as a function.
match_order

Match one order to another.
mk_formula

Construct a formula.
run_package_tests

Run package tests.
mapsyms

Map symbol names to referenced values if those values are string scalars (else throw).
mk_tmp_name_source

Produce a temp name generator with a given prefix.
run_wrapr_tests

Run wrapr package tests.
show,SrcFunction-method

S4 print method
view

Invoke a spreadsheet like viewer when appropriate.
show,UnaryFnList-method

S4 print method
apply_left_default

S3 dispatch on class of pipe_left_arg.
apply_right

S3 dispatch on class of pipe_right_argument.
grab_assignments_from_dots

Re-write captured ... arguments as assignments.
format.locum

Format a locum for presentation.
locum

Build a stand in for a future value to be placed in a pipe.
makeFunction_se

Build an anonymous function.
draw_framec

Render a simple data.frame in qchar_frame format.
print.locum

Print a locum presentation.
grepv

Return a vector of matches.
wrapfn

Wrap the source for an exprssion as a function.
apply_left.UnaryFn

Apply right wrapped function to argument on left.
as.list.UnaryFn

Get list of primative unary fns.
as.list.UnaryFnList

Get list of primative unary fns.
invert_perm

Invert a permutation.
parLapplyLBm

Memoizing wrapper for parLapplyLB
has_no_dup_rows

Check for duplicate rows.
lambda

Build an anonymous function.
clean_fit_glm

Fit a stats::glm without carying back large structures.
restrictToNameAssignments

Restrict an alias mapping list to things that look like name assignments
show,PartialFunction-method

S4 print method
partition_tables

Partition as set of tables into a list.
returnCapture

Return an error to a file, environment (no names) or callback
psagg

Pseudo aggregator.
clean_fit_lm

Fit a stats::lm without carying back large structures.
reduceexpand

Use function to reduce or expand arguments.
qs

Quote argument as a string.
format.SrcFunction

format step
format.UnaryFnList

format step
apply_left.default

S3 dispatch on class of pipe_left_arg.
%qc%

Inline quoting list/array concatenate.
%p%

Inline character paste0.
map_to_char

format a map.
split_at_brace_pairs

Split strings at -pairs.
[.Unpacker

Prepare for unpack or bind values into the calling environment.
[<-.Unpacker

Unpack or bind values into the calling environment.
srcfn

Wrap the source for an exprssion as a function.
as_fnlist

Wrap a list of UnaryFns as a UnaryFnList.
apply_left.locum

S3 dispatch on class of pipe_left_arg for a locum.
as_named_list

Capture named objects as a named list.
defineLambda

Define lambda function building function.
eval_dot_sequence

Evaluate a sequence of expressions with .-value substituted in.
dot_arrow

Pipe operator ("dot arrow", "dot pipe" or "dot arrow pipe").
evalb

eval(bquote(expr)) shortcut.
%in_block%

Inline let-block notation.
show,PartialNamedFn-method

S4 print method
map_upper

Map up-cased symbol names to referenced values if those values are string scalars (else throw).
named_map_builder

Named map builder.
lapplym

Memoizing wrapper for lapply.
grepdf

Grep for column names from a data.frame
let

Execute expr with name substitutions specified in alias.
uniques

Strict version of unique (without ...).
to

Unpack or bind values by names into the calling environment, eager eval (no-dot) variation.
seqi

Increasing whole-number sequence.
qc

Quoting version of c() array concatenate.
qae

Quote assignment expressions (name = expr, name := expr, name %:=% expr).
orderv

Order by a list of vectors.
sequence_as_function

Convert a sequence of expressions into a function.
unpack

Unpack or bind values by names into the calling environment.
pkgfn

Wrap the name of a function as a function.
pipe_impl

Pipe dispatch implementation.
qchar_frame

Build a quoted data.frame.
vapplym

Memoizing wrapper for vapply.
wrapr

wrapr: Wrap R Functions for Debugging and Parametric Programming
stop_if_dot_args

Stop with message if dot_args is a non-trivial list.
sinterp

Dot substitution.
sortv

Sort a data.frame.
strsplit_capture

Split a string, keeping separator regions
qe

Quote expressions.