crate() creates functions in a self-contained environment
(technically, a child of the base environment). This has two
advantages:
They can easily be executed in another process.
Their effects are reproducible. You can run them locally with the same results as on a different process.
Creating self-contained functions requires some care, see section below.
crate(
.fn,
...,
.parent_env = baseenv(),
.error_arg = ".fn",
.error_call = environment()
)A fresh formula or function. "Fresh" here means that
they should be declared in the call to crate(). See examples if
you need to crate a function that is already defined. Formulas
are converted to purrr-like lambda functions using
rlang::as_function().
Named arguments to declare in the environment of .fn.
The default of baseenv() ensures that the evaluation
environment of the crate is isolated from the search path. Specifying
another environment such as the global environment allows this condition to
be relaxed (but at the expense of no longer being able to rely on a local
run giving the same results as one in a different process).
An argument name as a string. This argument will be mentioned in error messages as the input that is at the origin of a problem.
The execution environment of a currently
running function, e.g. caller_env(). The function will be
mentioned in error messages as the source of the error. See the
call argument of abort() for more information.
They should call package functions with an explicit ::
namespace. This includes packages in the default search path with
the exception of the base package. For instance var() from the
stats package must be called with its namespace prefix:
stats::var(x).
They should declare any data they depend on. You can declare data
by supplying additional arguments or by unquoting objects with !!.
# You can create functions using the ordinary notation:
crate(function(x) stats::var(x))
#> <crate> 1.23 kB
#> * function: 672 B
#> function (x)
#> stats::var(x)
# Or the formula notation:
crate(~ stats::var(.x))
#> <crate> 1.68 kB
#> * function: 1.12 kB
#> function (..., .x = ..1, .y = ..2, . = ..1)
#> stats::var(.x)
# Declare data by supplying named arguments. You can test you have
# declared all necessary data by calling your crated function:
na_rm <- TRUE
fn <- crate(~ stats::var(.x, na.rm = na_rm))
try(fn(1:10))
#> Error in fn(1:10) : object 'na_rm' not found
# For small data it is handy to unquote instead. Unquoting inlines
# objects inside the function. This is less verbose if your
# function depends on many small objects:
fn <- crate(~ stats::var(.x, na.rm = !!na_rm))
fn(1:10)
#> [1] 9.166667
# One downside is that the individual sizes of unquoted objects
# won't be shown in the crate printout:
fn
#> <crate> 1.85 kB
#> * function: 1.29 kB
#> function (..., .x = ..1, .y = ..2, . = ..1)
#> stats::var(.x, na.rm = TRUE)
# The function or formula you pass to crate() should defined inside
# the crate() call, i.e. you can't pass an already defined
# function:
fn <- function(x) toupper(x)
try(crate(fn))
#> Error in crate(fn) : The function must be defined inside this call
# If you really need to crate an existing function, you can
# explicitly set its environment to the crate environment with the
# set_env() function from rlang:
crate(rlang::set_env(fn))
#> <crate> 952 B
#> * function: 392 B
#> function (x)
#> toupper(x)