Dot Pipe

John Mount

2023-08-19

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

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

That is: %.>% does not alter any function arguments that are not explicitly named. %.>% is designed to be explicit and simple.

The following two expressions should be equivalent:

library("wrapr")

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 in that many variations of expression work as expected. Example:

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

Regularity can be a big advantage in teaching and comprehension. Please see “In Praise of Syntactic Sugar” for discussion.

The dot arrow pipe has S3/S4 dispatch (please see “Dot-Pipe: an S3 Extensible Pipe for R”). 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 .().

A detail of R-style pipes is the right argument is held unevalauted (unless it is a name), so we can’t always use the class of the right hand side to dispatch. To work around this we suggest using .() notation, which in the context of the pipe means “evaluate early.” An example is given below:

f <- function() { sin }

# returns f() ignoring dot, not what we want
5 %.>% f()
## function (x)  .Primitive("sin")
# evaluates f() early then evaluates result with .-substitution rules
5 %.>% .(f())
## [1] -0.9589243