| Type: | Package |
| Title: | Multi-Paradigm Pipeline Implementation |
| Version: | 0.6.1.3 |
| Author: | Kun Ren <ken@renkun.me> |
| Maintainer: | Kun Ren <ken@renkun.me> |
| Description: | Provides various styles of function chaining methods: Pipe operator, Pipe object, and pipeline function, each representing a distinct pipeline model yet sharing almost a common set of features: A value can be piped to the first unnamed argument of a function and to dot symbol in an enclosed expression. The syntax is designed to make the pipeline more readable and friendly to a wide range of operations. |
| Depends: | R (≥ 2.15) |
| Date: | 2016-04-04 |
| Suggests: | testthat |
| License: | MIT + file LICENSE |
| URL: | https://renkun.me/pipeR, https://github.com/renkun-ken/pipeR, https://renkun.me/pipeR-tutorial |
| BugReports: | https://github.com/renkun-ken/pipeR/issues |
| ByteCompile: | TRUE |
| RoxygenNote: | 5.0.1 |
| NeedsCompilation: | no |
| Packaged: | 2016-04-04 08:55:01 UTC; Kun |
| Repository: | CRAN |
| Date/Publication: | 2016-04-04 11:49:28 |
The pipeR package
Description
pipeR implements various function chaining methods: %>>% operator,
Pipe object, and pipeline function. Each represents a distinct
pipeline model yet shares a common set of features designed to build
easy-to-read/write/maintain pipelines.
To learn more, please visit pipeR Tutorial.
Details
pipeR package defines a set of syntax tailored for unified, intuitive piping experience. The package is designed to help organize code as a streamline that is consistent with logic and intuition.
The following example shows how traditional code can be written in different function chaining styles.
Examples
# Traditional code:
plot(density(sample(mtcars$mpg, size = 10000, replace = TRUE),
kernel = "gaussian"), col = "red", main="density of mpg (bootstrap)")
# Operator-based pipeline using %>>%:
mtcars$mpg %>>%
sample(size = 10000, replace = TRUE) %>>%
density(kernel = "gaussian") %>>%
plot(col = "red", main = "density of mpg (bootstrap)")
# Object-based pipeline using Pipe():
Pipe(mtcars$mpg)$
sample(size = 10000, replace = TRUE)$
density(kernel = "gaussian")$
plot(col = "red", main = "density of mpg (bootstrap)")
# Argument-based pipeline using pipeline():
pipeline(mtcars$mpg,
sample(size = 10000, replace = TRUE),
density(kernel = "gaussian"),
plot(col = "red", main = "density of mpg (bootstrap)"))
# Expression-based pipeline using pipeline():
pipeline({
mtcars$mpg
sample(size = 10000, replace = TRUE)
density(kernel = "gaussian")
plot(col = "red", main = "density of mpg (bootstrap)")
})
Pipe an object forward
Description
The %>>% operator pipes the object on the left-hand side to the
right-hand side according to the syntax.
Usage
x %>>% expr
Arguments
x |
object |
expr |
expression |
Details
Pipe operator %>>% determines the piping mechanism by the syntax
of the expression on the right-hand side.
%>>% supports the following syntaxes:
1. Pipe to first unnamed argument:
Whenever a function name or call with or without parameters follows the operator, the left-hand side value will be piped to the right-hand side function as the first unnamed argument.
x %>>% f evaluated as f(x)
x %>>% f(...) evaluated as f(x,...)
x %>>% package::name(...) evaluated as package::name(x, ...)
2. Pipe to . in enclosed expression:
Whenever an expression following the operator is enclosed by {},
the expression will be evaluated with . representing the left-hand
side value. It is the same with expression enclosed with () unless
it contains a lambda expression or assignment expression.
x %>>% { expr } evaluated as { expr } given . = x
x %>>% ( expr ) evaluated as expr given . = x
3. Pipe by lambda expression:
A lambda expression is a formula whose left-hand side is a symbol used to represent the value being piped and right-hand side is an expression to be evaluated with the symbol.
x %>>% (p ~ expr) as expr given p = x
4. Pipe for side-effect:
If one only cares about the side effect (e.g. printing intermediate
results, plotting graphics, assigning value to symbol) of an expression
rather than its returned value, write a lambda expression that starts
with ~ indicating side effect (or branching, in the sense of
pipeline building).
x %>>% (~ f(.)) evaluated as {f(x); x}.
x %>>% (~ p ~ f(p)) evaluated as {f(x); x}
5. Pipe for assignment
Equal operator (=) and assignment operators (<- and ->) perform assignment.
This is particularly useful when one needs to save an intermediate value in the middle
of a pipeline without breaking it.
Assignment as side-effect
In general, x %>>% (~ y = ...) is evaluated as
y <- x %>>% (...) and returns x.
x %>>% (~ y) evaluated as y <- x and returns x,
where y must be a symbol.
x %>>% (~ y = f(.)) evaluated as y <- f(x) and returns
x.
x %>>% (~ y = p ~ f(p)) evaluated as y <- f(x) and
returns x.
Piping with assignment
In general, x %>>% (y = ...) is evaluated as
y <- x %>>% (...).
x %>>% (y = f(.)) evaluated as y <- f(x) and returns
f(x).
x %>>% (y = p ~ f(p)) evaluated as y <- f(x) and returns
f(x).
The equal sign above can be interchangeably used as the assignment operator <-.
Note that the global assignment operator <<- and ->> in a pipeline also
performs global assignment that is subject to side-effect outside the calling
environment.
In some cases, users might need to create a group of symbols. The following code
calls assign to dynamically determine the symbol name when its value is
evaluated.
for (i in 1:5) rnorm(i) %>>% (assign(paste0("rnorm", i), .))
To avoid exporting a symbol to the calling environment, use a symbol name
starting with . like
6. Pipe for element extraction:
If a symbol is enclosed within (), it tells the operator to
extract element from the left-hand side value. It works with vector,
list, environment and all other objects for which [[]]
is defined. Moreover, it also works with S4 object.
x %>>% (name) as x[["name"]] when x is
list, environment, data.frame, etc; and
x@name when x is S4 object.
7. Pipe to string:
If an object is piped to a single character value, then the string will
be cat() and starts a new paragraph. This is useful for indicating the
executing process of a pipeline.
x %>>% "print something" %>>% f(y) will cat("print something")
and then evaluate f(x,y).
8. Pipe for questioning:
If a lambda expression start with ?, the expression will be a side
effect printing the syntax and the value of the expression. This is a
light-weight version of side-effect piping and can be useful for simple
inspection and debugging for pipeline operations.
x %>>% (? expr) will print the value of expr and
return x, just like a question.
x %>>% ("title" ? expr) will print "title" as the question, the
value of expr, and return x.
Examples
## Not run:
# Pipe as first-argument to a function name
rnorm(100) %>>% plot
# Pipe as first-argument to a function call
rnorm(100) %>>% plot()
rnorm(100) %>>% plot(col="red")
rnorm(100) %>>% plot(col="red",main=length(.))
# Pipe as first-argument to a function call in namespace
# (in this case, parentheses are required)
rnorm(100) %>>% base::mean()
# Pipe to . in an expression enclosed by braces
representing the piped object
rnorm(100) %>>% { plot(.,col="red",main=length(.)) }
# Pipe to . in an expression enclosed by parentheses
representing the piped object
rnorm(100) %>>% (plot(.,col="red",main=length(.)))
# Pipe to an expression enclosed by parentheses with
lambda expression in the form of x ~ f(x).
rnorm(100) %>>% (x ~ plot(x,col="red",main=length(x)))
# Pipe to an expression for side effect and return
# the input value
rnorm(100) %>>%
(~ cat("Number of points:",length(.))) %>>%
summary
rnorm(100) %>>%
(~ x ~ cat("Number of points:",length(x))) %>>%
summary
# Assign the input value to a symbol in calling environment
# as side-effect
mtcars %>>%
subset(mpg <= mean(mpg)) %>>%
(~ sub_mtcars) %>>%
summary
# Assign to a symbol the value calculated by lambda expression
# as side effect
mtcars %>>%
(~ summary_mtcars = summary(.)) %>>%
(~ lm_mtcars = df ~ lm(mpg ~ ., data = df)) %>>%
subset(mpg <= mean(mpg)) %>>%
summary
# Modifying values in calling environment
"col_" %>>%
paste0(colnames(mtcars)) %>>%
{names(mtcars) <- .}
rnorm(100) %>>% {
num_mean <- mean(.)
num_sd <- sd(.)
num_var <- var(.)
}
rnorm(100) %>>% {
.mean <- mean(.)
.sd <- sd(.)
ci <- .mean + c(-1,1) * 1.96 * .sd
}
for(i in 1:10) rnorm(i) %>>% (assign(paste0("var", i), .))
# Pipe for element extraction
mtcars %>>% (mpg)
# Pipe for questioning and printing
rnorm(100) %>>%
(? summary(.)) %>>%
plot(col="red")
mtcars %>>%
"data prepared" %>>%
lm(formula = mpg ~ wt + cyl) %>>%
summary %>>%
coef
mtcars %>>%
("Sample data" ? head(., 3)) %>>%
lm(formula = mpg ~ wt + cyl) %>>%
summary %>>%
coef
# Pipe to an anomymous function
rnorm(100) %>>% (function(x) mean(x))()
rnorm(100) %>>% {function(x) mean(x)}()
# Pipe to an enclosed function to make a closure
z <- rnorm(100) %>>% (function(x) mean(x+.))
z(1) # 3
z <- rnorm(100) %>>% {function(x) mean(x+.)}
z(1) # 3
# Data manipulation with dplyr
library(dplyr)
iris %>>%
mutate(Sepal.Size=Sepal.Length*Sepal.Width,
Petal.Size=Petal.Length*Petal.Width) %>>%
select(Sepal.Size,Petal.Size,Species) %>>%
group_by(Species) %>>%
do(arrange(.,desc(Sepal.Size+Petal.Size)) %>>% head(3))
# Data manipulation with rlist
library(rlist)
list(1,2,3) %>>%
list.map(. + 1) %>>%
list.filter(. <= 5) %>>%
list.sort(.)
## End(Not run)
Create a Pipe object that stores a value and allows command chaining with $.
Description
Create a Pipe object that stores a value and allows command chaining with $.
Usage
Pipe(value = NULL)
Arguments
value |
value to pipe (default is |
Details
Pipe() function creates a Pipe object that provides object-like command
chaining mechanism, which avoids using external operator and can be cleaner than
operator-based pipline.
Pipe() creates a Pipe object that allows using $ to perform
first-argument piping, call .() to evaluate an expression with .
or symbol defined by lambda expression, for side effect, or simply extract an
element from the stored value. $value or [] ends a pipeline and
extracts its final value.
The functionality of Pipe object fully covers that of the pipe operator %>>%
and provides more features. For example, Pipe object supports directly subsetting
$value by [...], extracting element by [[...]], and assigning value
by $item <-, [...] <-, and [[...]] <-.
A typical usage of Pipe object is to start with Pipe() and end with
$value or [].
print() and str() are implemented for Pipe object.
Use header = FALSE to suppress Pipe header message in printed results.
Use options(Pipe.header = FASLE) to suppress it globally.
If the Pipe object is used in more than one pipelines, a recommended usage is to name the
object specially so that it is easy to distinguish the Pipe object from the value it
stores. For example, it can start with p.
Value
Pipe object
Examples
## Not run:
# Pipe as first-argument using $
Pipe(rnorm(100))$mean()
Pipe(rnorm(100))$plot(col="red")
# Extract the value from the Pipe object using []
Pipe(rnorm(100))$c(4,5) []
# Pipe to an exrepssion with . or symbol defined in
# lambda expression to represent the object
Pipe(rnorm(100))$.(1 + .) []
Pipe(rnorm(100))$.(x ~ 1 + x) []
# Pipe for side effect
Pipe(rnorm(100))$
.(~ cat("number:",length(.),"\n"))$
summary()
Pipe(rnorm(100))$
.(~ x ~ cat("number:",length(x),"\n"))$
summary()
# Assignment
Pipe(rnorm(100))$
.(~ x)$
mean()
Pipe(rnorm(100))$
.(~ x <- length(.))$
mean()
Pipe(rnorm(100))%
.(x <- c(min(.),max(.)))$
mean()
# Extract element with \code{.(name)}
Pipe(mtcars)$lm(formula = mpg ~ cyl + wt)$.(coefficients)
# Command chaining
Pipe(rnorm(100,mean=10))$
log()$
diff()$
plot(col="red")
Pipe(rnorm(100))$
density(kernel = "rect")$
plot(col = "blue")
# Store an continue piping
pipe1 <- Pipe(rnorm(100,mean=10))$log()$diff()
pipe1$plot(col="red")
# Subsetting, extracting, and assigning
p <- Pipe(list(a=1,b=2))
p["a"]
p[["a"]]
p$a <- 2
p["b"] <- NULL
p[["a"]] <- 3
p[length(.)] # . = p$value
# Data manipulation with dplyr
library(dplyr)
Pipe(mtcars)$
select(mpg,cyl,disp,hp)$
filter(mpg <= median(mpg))$
mutate(rmpg = mpg / max(mpg))$
group_by(cyl)$
do(data.frame(mean=mean(.$rmpg),median=median(.$rmpg))) []
# Graphics with ggvis
library(ggvis)
Pipe(mtcars)$
ggvis(~ mpg, ~ wt)$
layer_points()
# Data manipulation with rlist
library(rlist)
Pipe(list(1,2,3))$
list.map(. + 1)$
list.filter(. <= 5)$
list.sort(.) []
# Lazy evaluation
p1 <- Pipe(mtcars)$
ggvis(~ mpg, ~ wt)
p1$layer_points()
p1$layer_bars()
# Stored Pipe
f1 <- Pipe(rnorm(100))$plot
f1(col="red")
f1(col="green")
## End(Not run)
Evaluate an expression pipeline
Description
Evaluate an expression pipeline enclosed by {} or a sequence of expressions
as as pipeline. This functions works to chain expressions without using %>>%
operator but produce the same result.
Usage
pipeline(...)
Arguments
... |
Pipeline expressions. Supply multiple pipeline expressions as arguments or
only an enclosed expression within |
Details
When pipeline(...) is called with multiple arguments, the arguments will be
regarded as pipeline expressions.
When pipeline(...) is called with a single argument, the argument is expected to
be a block expression enclosed by {} in which each expression will be regarded
as a pipeline expression.
The pipeline expressions will be chained sequentially by %>>% and be evaluated
to produce the same results as if using the pipe operator.
Examples
pipeline(1:10, sin, sum)
pipeline(1:10, plot(col = "red", type = "l"))
pipeline(mtcars,
lm(formula = mpg ~ cyl + wt),
summary,
coef)
pipeline({
mtcars
lm(formula = mpg ~ cyl + wt)
summary
coef
})
pipeline({
mtcars
"Sample data" ? head(., 3)
lm(formula = mpg ~ cyl + wt)
~ lmodel
summary
? .$r.squared
coef
})
pipeline({
mtcars
"estimating a linear model ..."
lm(formula = mpg ~ cyl + wt)
"summarizing the model ..."
summary
})