Introduction
frite is a package that enable anyone to easily write and modify functions with code. The tools it provides have applications in code generation or metaprogramming. It can also be used to inject, assign, or remove code in a function.
If you want to view the code, here is the GitHub repository.
The functions
- Diagnostic
tictocify
returns a nearly identical timed version of its inputis.output.same
performs call on multiple functions and sees if they match
- Modification
line_assign
insertsassign()
into a functionline_insert
inserts code into a functionline_remove
removes code from a functioncopy_args
copies the arguments of one function to another
- Helping
list_body
converts function body to a listplot_body
plotslist_body()
so you can inspect the body
Diagnostic functions
# Defining a new function
reduce_timed <- tictocify(reduce)
# Now to test it against the original reduce
reduce_timed(1:100000, sum, .init = 0)
#> 0.21 sec elapsed
#> [1] 5000050000
is.output.same(reduce_timed(1:100000, sum, .init = 0), reduce)
#> 0.16 sec elapsed
#> [1] TRUE
tictocify
will return a nearly identical timed version of a function. It does this by creating a function call and inserting tic()
, toc()
, and a return statement around the call.
is.output.same
evaluates the call in the first argument and replaces the function in the first call and re-evaluates it with a new output and checks that they are identical.
# Constructing a different version of reduce_timed
(reduce_timed1 <- line_insert(reduce, after_line = 1, quote(tic())))
#> function (.x, .f, ..., .init)
#> {
#> tic()
#> reduce_impl(.x, .f, ..., .init = .init, .left = TRUE)
#> }
#> <environment: namespace:purrr>
(reduce_timed1 <- line_assign(reduce_timed1, line = 3, 'value'))
#> function (.x, .f, ..., .init)
#> {
#> tic()
#> assign("value", reduce_impl(.x, .f, ..., .init = .init, .left = TRUE))
#> }
#> <environment: namespace:purrr>
(reduce_timed1 <- line_insert(reduce_timed1, after_line = 3, quote(toc())))
#> function (.x, .f, ..., .init)
#> {
#> tic()
#> assign("value", reduce_impl(.x, .f, ..., .init = .init, .left = TRUE))
#> toc()
#> }
#> <environment: namespace:purrr>
(reduce_timed1 <- line_insert(reduce_timed1, after_line = 4,
quote(return(value))))
#> function (.x, .f, ..., .init)
#> {
#> tic()
#> assign("value", reduce_impl(.x, .f, ..., .init = .init, .left = TRUE))
#> toc()
#> return(value)
#> }
#> <environment: namespace:purrr>
is.output.same(reduce_timed(1:100000, sum, .init = 0), reduce_timed1)
#> 0.18 sec elapsed
#> 0.16 sec elapsed
#> [1] TRUE
Note: Everything above can be piped.
These types of modifications can be difficult to make sequentially, so there are a couple of helper functions to allow you to see what you’re doing.
plot_body(map)
#> function (.x, .f, ...)
#> {
#> .f <- as_mapper(.f, ...)
#> .Call(map_impl, environment(), ".x", ".f", "list")
#> }
#> <bytecode: 0x00000000139208e8>
#> <environment: namespace:purrr>
graphics::rect(xleft = -.15, ybottom = -.2, xright = 1.1, ytop = 1.2, xpd = TRUE)
map_hello <- map %>%
line_insert(after_line = 1, quote(print("Hello!")))
list_body(map_hello)
#> [[1]]
#> `{`
#>
#> [[2]]
#> print("Hello!")
#>
#> [[3]]
#> .f <- as_mapper(.f, ...)
#>
#> [[4]]
#> .Call(map_impl, environment(), ".x", ".f", "list")
map_hello(list(1, 2, "b"), assertthat::is.number)
#> [1] "Hello!"
#> [[1]]
#> [1] TRUE
#>
#> [[2]]
#> [1] TRUE
#>
#> [[3]]
#> [1] FALSE
Recursively building functions
You can use the modification functions to build functions with recursion. A simple example is below.
spammer <- function() {}
add_print <- function(.f, n) {
.f <- line_insert(.f, 1, quote(print("a")))
n <- n - 1
if (n > 0) return(add_print(.f, n))
if (n == 0) return(.f)
}
add_print(spammer, 5)
#> function ()
#> {
#> print("a")
#> print("a")
#> print("a")
#> print("a")
#> print("a")
#> }
If you want to learn more, you can view the reference manual or install frite
and begin experimenting.
Installation
You can install frite
from cran:
install.packages("frite")
Or you can install the development version from github:
install.packages("devtools")
devtools::install_github("visuelledata/frite")