Skip to content
Permalink
main
Switch branches/tags
Go to file
 
 
Cannot retrieve contributors at this time
#' Pipe
#'
#' Pipe an object forward into a function or call expression.
#'
#' @param lhs A value or the magrittr placeholder.
#' @param rhs A function call using the magrittr semantics.
#' @details
#' \subsection{Using `%>%` with unary function calls}{
#'
#' When functions require only one argument, `x %>% f` is equivalent
#' to `f(x)` (not exactly equivalent; see technical note below.)
#'
#' }
#' \subsection{Placing `lhs` as the first argument in `rhs` call}{
#'
#' The default behavior of `%>%` when multiple arguments are required
#' in the `rhs` call, is to place `lhs` as the first argument, i.e.
#' `x %>% f(y)` is equivalent to `f(x, y)`.
#' }
#' \subsection{Placing `lhs` elsewhere in `rhs` call}{
#'
#' Often you will want `lhs` to the `rhs` call at another position than the first.
#' For this purpose you can use the dot (`.`) as placeholder. For example,
#' `y %>% f(x, .)` is equivalent to `f(x, y)` and
#' `z %>% f(x, y, arg = .)` is equivalent to `f(x, y, arg = z)`.
#' }
#'
#' \subsection{Using the dot for secondary purposes}{
#'
#' Often, some attribute or property of `lhs` is desired in the `rhs` call in
#' addition to the value of `lhs` itself, e.g. the number of rows or columns.
#' It is perfectly valid to use the dot placeholder several times in the `rhs`
#' call, but by design the behavior is slightly different when using it inside
#' nested function calls. In particular, if the placeholder is only used
#' in a nested function call, `lhs` will also be placed as the first argument!
#' The reason for this is that in most use-cases this produces the most readable
#' code. For example, `iris %>% subset(1:nrow(.) %% 2 == 0)` is
#' equivalent to `iris %>% subset(., 1:nrow(.) %% 2 == 0)` but
#' slightly more compact. It is possible to overrule this behavior by enclosing
#' the `rhs` in braces. For example, `1:10 %>% {c(min(.), max(.))}` is
#' equivalent to `c(min(1:10), max(1:10))`.
#' }
#'
#' \subsection{Using `%>%` with call- or function-producing `rhs`}{
#'
#' It is possible to force evaluation of `rhs` before the piping of `lhs` takes
#' place. This is useful when `rhs` produces the relevant call or function.
#' To evaluate `rhs` first, enclose it in parentheses, i.e.
#' `a %>% (function(x) x^2)`, and `1:10 %>% (call("sum"))`.
#' Another example where this is relevant is for reference class methods
#' which are accessed using the `$` operator, where one would do
#' `x %>% (rc$f)`, and not `x %>% rc$f`.
#' }
#'
#' \subsection{Using lambda expressions with `%>%`}{
#'
#' Each `rhs` is essentially a one-expression body of a unary function.
#' Therefore defining lambdas in magrittr is very natural, and as
#' the definitions of regular functions: if more than a single expression
#' is needed one encloses the body in a pair of braces, \code{\{ rhs \}}.
#' However, note that within braces there are no "first-argument rule":
#' it will be exactly like writing a unary function where the argument name is
#' "`.`" (the dot).
#'
#' }
#' \subsection{Using the dot-place holder as `lhs`}{
#'
#' When the dot is used as `lhs`, the result will be a functional sequence,
#' i.e. a function which applies the entire chain of right-hand sides in turn
#' to its input. See the examples.
#' }
#'
#' @section Technical notes:
#' The magrittr pipe operators use non-standard evaluation. They capture
#' their inputs and examines them to figure out how to proceed. First a function
#' is produced from all of the individual right-hand side expressions, and
#' then the result is obtained by applying this function to the left-hand side.
#' For most purposes, one can disregard the subtle aspects of magrittr's
#' evaluation, but some functions may capture their calling environment,
#' and thus using the operators will not be exactly equivalent to the
#' "standard call" without pipe-operators.
#'
#'
#' Another note is that special attention is advised when using non-magrittr
#' operators in a pipe-chain (`+, -, $,` etc.), as operator precedence will impact how the
#' chain is evaluated. In general it is advised to use the aliases provided
#' by magrittr.
#'
#' @seealso \code{\link{\%<>\%}}, \code{\link{\%T>\%}}, \code{\link{\%$\%}}
#'
#' @examples
#' # Basic use:
#' iris %>% head
#'
#' # Use with lhs as first argument
#' iris %>% head(10)
#'
#' # Using the dot place-holder
#' "Ceci n'est pas une pipe" %>% gsub("une", "un", .)
#'
#' # When dot is nested, lhs is still placed first:
#' sample(1:10) %>% paste0(LETTERS[.])
#'
#' # This can be avoided:
#' rnorm(100) %>% {c(min(.), mean(.), max(.))} %>% floor
#'
#' # Lambda expressions:
#' iris %>%
#' {
#' size <- sample(1:10, size = 1)
#' rbind(head(., size), tail(., size))
#' }
#'
#' # renaming in lambdas:
#' iris %>%
#' {
#' my_data <- .
#' size <- sample(1:10, size = 1)
#' rbind(head(my_data, size), tail(my_data, size))
#' }
#'
#' # Building unary functions with %>%
#' trig_fest <- . %>% tan %>% cos %>% sin
#'
#' 1:10 %>% trig_fest
#' trig_fest(1:10)
#'
#' @rdname pipe
#' @export
`%>%` <- function(lhs, rhs) {
lhs <- substitute(lhs)
rhs <- substitute(rhs)
kind <- 1L
env <- parent.frame()
lazy <- TRUE
.External2(magrittr_pipe)
}
#' Lazy and eager pipes
#'
#' Assign these pipe variants to an infix symbol like `%>%`.
#'
#' @inheritParams %>%
#' @keywords internal
#' @export
pipe_eager_lexical <- function(lhs, rhs) {
lhs <- substitute(lhs)
rhs <- substitute(rhs)
kind <- 1L
env <- parent.frame()
sym <- sys.call()[[1]]
.External2(magrittr_pipe)
}
#' @rdname pipe_eager_lexical
#' @export
pipe_lazy_masking <- function(lhs, rhs) {
lhs <- substitute(lhs)
rhs <- substitute(rhs)
kind <- 1L
env <- parent.frame()
lazy <- TRUE
sym <- sys.call()[[1]]
.External2(magrittr_pipe)
}
#' @rdname pipe_eager_lexical
#' @export
pipe_nested <- function(lhs, rhs) {
lhs <- substitute(lhs)
rhs <- substitute(rhs)
kind <- 1L
env <- parent.frame()
nested <- TRUE
sym <- sys.call()[[1]]
.External2(magrittr_pipe)
}
#' Assignment pipe
#'
#' Pipe an object forward into a function or call expression and update the
#' `lhs` object with the resulting value.
#'
#' @param lhs An object which serves both as the initial value and as target.
#' @param rhs a function call using the magrittr semantics.
#'
#' @details The assignment pipe, \code{\%<>\%}, is used to
#' update a value by first piping it into one or more `rhs` expressions, and
#' then assigning the result. For example, \code{some_object \%<>\%
#' foo \%>\% bar} is equivalent to \code{some_object <- some_object \%>\% foo
#' \%>\% bar}. It must be the first pipe-operator in a chain, but otherwise it
#' works like \code{\link{\%>\%}}.
#'
#' @seealso \code{\link{\%>\%}}, \code{\link{\%T>\%}}, \code{\link{\%$\%}}
#'
#' @examples
#' iris$Sepal.Length %<>% sqrt
#'
#' x <- rnorm(100)
#'
#' x %<>% abs %>% sort
#'
#' is_weekend <- function(day)
#' {
#' # day could be e.g. character a valid representation
#' day %<>% as.Date
#'
#' result <- day %>% format("%u") %>% as.numeric %>% is_greater_than(5)
#'
#' if (result)
#' message(day %>% paste("is a weekend!"))
#' else
#' message(day %>% paste("is not a weekend!"))
#'
#' invisible(result)
#' }
#'
#' @rdname compound
#' @export
`%<>%` <- function(lhs, rhs) {
lhs <- substitute(lhs)
rhs <- substitute(rhs)
kind <- 2L
lazy <- TRUE
env <- parent.frame()
.External2(magrittr_pipe)
}
#' Tee pipe
#'
#' Pipe a value forward into a function- or call expression and return the
#' original value instead of the result. This is useful when an expression
#' is used for its side-effect, say plotting or printing.
#'
#' @param lhs A value or the magrittr placeholder.
#' @param rhs A function call using the magrittr semantics.
#'
#' @details The tee pipe works like \code{\link{\%>\%}}, except the
#' return value is `lhs` itself, and not the result of `rhs` function/expression.
#'
#' @seealso \code{\link{\%>\%}}, \code{\link{\%<>\%}}, \code{\link{\%$\%}}
#'
#' @examples
#' rnorm(200) %>%
#' matrix(ncol = 2) %T>%
#' plot %>% # plot usually does not return anything.
#' colSums
#'
#' @rdname tee
#' @export
`%T>%` <- function(lhs, rhs) {
lhs <- substitute(lhs)
rhs <- substitute(rhs)
kind <- 3L
lazy <- TRUE
env <- parent.frame()
.External2(magrittr_pipe)
}
#' Exposition pipe
#'
#' Expose the names in `lhs` to the `rhs` expression. This is useful when functions
#' do not have a built-in data argument.
#'
#' @param lhs A list, environment, or a data.frame.
#' @param rhs An expression where the names in lhs is available.
#'
#' @details Some functions, e.g. `lm` and `aggregate`, have a
#' data argument, which allows the direct use of names inside the data as part
#' of the call. This operator exposes the contents of the left-hand side object
#' to the expression on the right to give a similar benefit, see the examples.
#' @seealso \code{\link{\%>\%}}, \code{\link{\%<>\%}}, \code{\link{\%T>\%}}
#'
#' @examples
#' iris %>%
#' subset(Sepal.Length > mean(Sepal.Length)) %$%
#' cor(Sepal.Length, Sepal.Width)
#'
#' data.frame(z = rnorm(100)) %$%
#' ts.plot(z)
#'
#' @rdname exposition
#' @export
`%$%` <- function(lhs, rhs) {
lhs <- substitute(lhs)
rhs <- substitute(rhs)
kind <- 4L
lazy <- TRUE
env <- parent.frame()
.External2(magrittr_pipe)
}
new_lambda <- function(exprs, env) {
`_function_list` <- lapply(exprs, as_pipe_fn, env)
structure(
function(value) freduce(value, `_function_list`),
class = c("fseq", "function")
)
}
lambda_fmls <- as.pairlist(alist(. = ))
as_pipe_fn <- function(expr, env) {
eval(call("function", lambda_fmls, expr), env)
}
#' FAQ: What is the gender of the pipe?
#'
#' In Magritte's original quote "Ceci n'est pas une pipe," the word
#' "pipe" is feminine. However the magrittr package quotes it as
#' "Ceci n'est pas un pipe," with a masculine "pipe." This
#' lighthearted misappropriation is intentional. Whereas the
#' object represented in Magritte's painting (a pipe that you can
#' smoke) is feminine in the French language, a computer pipe
#' (which is an Anglicism in French) is masculine.
#'
#' @name faq-pipe-gender
NULL
#' Eager pipe
#'
#' @description
#' Whereas `%>%` is lazy and only evaluates the piped expressions when
#' needed, `%!>%` is eager and evaluates the piped input at each step.
#' This produces more intuitive behaviour when functions are called
#' for their side effects, such as displaying a message.
#'
#' Note that you can also solve this by making your function
#' strict. Call `force()` on the first argument in your function to
#' force sequential evaluation, even with the lazy `%>%` pipe.
#' See the examples section.
#'
#' @inheritParams %>%
#'
#' @examples
#' f <- function(x) {
#' message("foo")
#' x
#' }
#' g <- function(x) {
#' message("bar")
#' x
#' }
#' h <- function(x) {
#' message("baz")
#' invisible(x)
#' }
#'
#' # The following lazy pipe sequence is equivalent to `h(g(f()))`.
#' # Given R's lazy evaluation behaviour,`f()` and `g()` are lazily
#' # evaluated when `h()` is already running. This causes the messages
#' # to appear in reverse order:
#' NULL %>% f() %>% g() %>% h()
#'
#' # Use the eager pipe to fix this:
#' NULL %!>% f() %!>% g() %!>% h()
#'
#' # Or fix this by calling `force()` on the function arguments
#' f <- function(x) {
#' force(x)
#' message("foo")
#' x
#' }
#' g <- function(x) {
#' force(x)
#' message("bar")
#' x
#' }
#' h <- function(x) {
#' force(x)
#' message("baz")
#' invisible(x)
#' }
#'
#' # With strict functions, the arguments are evaluated sequentially
#' NULL %>% f() %>% g() %>% h()
#'
#' # Instead of forcing, you can also check the type of your functions.
#' # Type-checking also has the effect of making your function lazy.
#'
#' @name pipe-eager
#' @export
`%!>%` <- pipe_eager_lexical