Wrap R Tools for Debugging and Parametric Programming

Tools for writing and debugging R code. Provides: 'let()' (converts non-standard evaluation interfaces to parametric standard evaluation interfaces, inspired by 'gtools:strmacro()' and 'base::bquote()'), '%.>%' dot-pipe (an 'S3' configurable pipe), 'build_frame()'/'draw_frame()' ('data.frame' example tools), 'qc()' (quoting concatenate), ':=' (named map builder), and more.


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

Introduction

Primary wrapr services include:

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".

library("wrapr")
 
a <- 7
 
let(
  c(VAR = 'a'),
  
  VAR + VAR
)

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).

%.>% (dot pipe or dot arrow)

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

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 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}
}

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"

:= (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

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.

News

wrapr 1.8.6 2019-04-02

wrapr 1.8.5 2019-03-24

  • More tests.
  • Be more careful with formals().
  • Add frame checking utils.
  • Doc fixes.

wrapr 1.8.4 2019-02-19

  • Add run_packages_tests() and run_wrapr_tests().
  • Move to RUnit tests.
  • More args to clean_fit.

wrapr 1.8.3 2019-01-29

  • Add string strsplit_capture() and dotsubs().
  • better bquote_function() and evalb() examples.
  • Allow comparisions in mk_formula(), and general improvements.

wrapr 1.8.2 2019-01-04

  • Add paste(class(), collapse=" ").
  • Add seqi().
  • Add evalb().

wrapr 1.8.1 2018-12-13

  • Fix as_fn() environment assignment.

wrapr 1.8.0 2018-12-11

  • Add generic unary functions.
  • Add .() pipe escaping.
  • Add clean lm() and glm() fitters.
  • Add split_at_brace_pairs.
  • Documentation fixes.
  • Error msg fix.
  • Add %p%, and %.%.

wrapr 1.7.0 2018-11-15

  • bquote enable qc() and other quoting methods.
  • Preserve NA types in draw_frame.
  • Add VectorizeM, vapplym, lapplym.
  • Add bquote_function().
  • Export underbar version of apply_left_default to get non-S3 version of code.
  • Better string concat example.
  • Add %c% and %qc%.
  • Allow qc() to call c().

wrapr 1.6.3 2018-10-03

  • Make sure parent.frame() is unambiguosly resovled (force()).
  • qe(), qae(), qs() now return character vectors instead of lists.
  • Add psagg().
  • Add grepv().
  • More examples in SubstitutionModes vignette (show we don't need special pairlist case).
  • Allow no-intercept version of formula.

wrapr 1.6.2 2018-09-10

  • Add mk_formula().
  • Documentation fixes.
  • Add %in_block% operator notation.
  • Add orderv().

wrapr 1.6.1 2018-08-21

  • More restrictive apply_right_S4.
  • Clear methods note.

wrapr 1.6.0 2018-08-01

  • S4 dispatch apply_right_S4.
  • split based partition_tables().
  • Allow drawing of empty data.frames.
  • Documentation fixes.

wrapr 1.5.1 2018-07-07

  • make pipe_impl public (but keyworld internal).
  • fix draw_frame quoting.
  • drop old pipe fns.

wrapr 1.5.0 2018-06-13

  • Rationalize and re-name pipe interfaces to apply_right and apply_left.
  • Fix qc() eval environment and recursion.
  • Add %?% coalescing operator.
  • Add reduce/expand operators.
  • Dot pipe tries to preserve names in function calls.
  • Improve error checking and reporting.
  • Add uniques().
  • Add partition_tables() and execute_parallel().

wrapr 1.4.1 2018-05-17

  • Move dot assignment into S3 step.
  • Refine error checking.
  • Minor documentation fixes.
  • Fix print/visibility treatment.
  • Remove special 1-key case from := .
  • draw_frame NA handling.
  • Add view().

wrapr 1.4.0 2018-04-03

  • More tests and checks.
  • Allow lookups at the top level ($, [], [[]], ::, :::, @).
  • Starting enforcing strict piping rules (with usable error messages).
  • Move base_fns to https://gist.github.com/JohnMount/1982127318654c8631203e5b5d4946ac and seplyr.
  • Minor documentation fixes/improvements.
  • Extend map_to_char() to work without names.
  • wrapr_function right-dispatch falls back to pipe_step left-disptach as default.

wrapr 1.3.0 2018-03-12

  • base_fns- slight stregnthenings of base operators for piping.
  • draw_frame et. al.- functions for building example data.frames.

wrapr 1.2.0 2018-02-21

  • Add map_upper.
  • Accept x=y in qae().
  • Strengthen :=.
  • Add left S3 dispatch through pipe_step.
  • Add right S3 dispatch through wrapr_function.
  • Add match_order.
  • Remove deprecated methods.
  • Move mk_tmp_name_source to this package.
  • Add stop_if_dot_args.

wrapr 1.1.1 2018-01-20

  • Fix some null/blank substitution issues.
  • Minor documentation improvements.

wrapr 1.1.0 2018-01-03

  • minor doc improvements.
  • fix deparse in qae() and qe().
  • Deprecate ateval(), seval(), beval(), and "stringsubs".
  • add qs().
  • add dereference and class-supplied function to pipes.

wrapr 1.0.2 2017-12-13

  • add "to dot" pipe.
  • harden := a bit.
  • let qc() have names.
  • add qae().
  • add map_to_char().

wrapr 1.0.1 2017-11-17

  • Better error msgs.
  • Bit more debugging info.
  • Add grepdf() and qc().

wrapr 1.0.0 2017-10-04

  • Add mapsyms() function.

wrapr 0.4.2 2017-08-31

  • Work on location of lambda-definition (do NOT write into environment until asked).
  • Minor check fixes.

wrapr 0.4.1 2017-08-24

  • Do not insist let-mapping be invertible.
  • Migrate named map builder and lambda from seplyr.

wrapr 0.4.0 2017-07-22

  • Allow non-strict names.
  • Insist let-mapping be invertible.

wrapr 0.3.0 2017-07-08

  • Introduce "dot arrow" pipe %.>%

wrapr 0.2.0 2017-07-05

  • Switch to abstract syntax tree substitution.
  • Allow variable swaps.

wrapr 0.1.3 2017-06-13

  • More flexible treatment of NULL.
  • Add non string based version of let() replacement.

wrapr 0.1.2 2017-04-13

  • add ateval()

wrapr 0.1.1 2017-03-13

  • Allow names in let.

wrapr 0.1.0 2017-02-10

  • First version (some fns, from replyr package).

Reference manual

It appears you don't have a PDF plugin for this browser. You can click here to download the reference manual.

install.packages("wrapr")

1.8.6 by John Mount, 2 months ago


https://github.com/WinVector/wrapr, http://winvector.github.io/wrapr/


Report a bug at https://github.com/WinVector/wrapr/issues


Browse source code at https://github.com/cran/wrapr


Authors: John Mount [aut, cre] , Nina Zumel [aut] , Win-Vector LLC [cph]


Documentation:   PDF Manual  


GPL-3 license


Imports utils, methods, graphics, stats

Suggests parallel, knitr, rmarkdown, RUnit, R.rsp


Imported by RcppDynProg, WVPlots, cdata, rqdatatable, rquery, sigr, vtreat.

Depended on by replyr, seplyr.


See at CRAN