partial {gestalt} | R Documentation |
Fix a Number of Arguments to a Function
Description
partial()
enables
partial application:
given a function, it fixes the value of selected arguments to produce a
function of the remaining arguments.
departial()
undoes the application of partial()
by returning the original
function.
Usage
partial(..f, ...)
departial(..f)
Arguments
..f |
Function. |
... |
Argument values of |
Details
Even while partial()
truncates formals, it remains compatible with
functions that use missing()
to test whether a
specified argument was supplied in a call. For example,
draw3 <- partial(sample, size = 3)
works as a function that randomly
draws three elements, even though sample()
invokes missing(size)
and
draw3()
has the form function(x, replace, prob) {...}
.
Because partially applied functions call the original function in an ad hoc
environment, impure functions that depend on the calling context as a
value, rather than as a lexical scope, may not be amenable to
partial()
. For example, partial(ls, all.names = TRUE)()
is not
equivalent to ls(all.names = TRUE)
, because ls()
inspects the calling
environment to produce its value, whereas partial(ls, all.names = TRUE)()
calls ls(all.names = TRUE)
from an (ephemeral) evaluation environment.
Value
partial()
returns a function whose formals are a
truncation of the formals of ..f
(as a closure) by the fixed arguments.
NB the original default values do not appear in the formals of a
partialized function, but are nonetheless applied when the function is
called.
The function partial(..f)
is identical to ..f
.
In conformance with R's calling convention, fixed argument values are lazy promises. Moreover, when forced, they are tidily evaluated. Lazy evaluation of fixed arguments can be overridden via unquoting, see ‘Examples’.
When ..f
is a partially applied function, departial(..f)
is the
(closure of) the underlying function. For ordinary (non-partially applied)
functions, departial(..f)
is identical to ..f
.
Examples
# Arguments can be fixed by name
draw3 <- partial(sample, size = 3)
draw3(letters)
# Arguments can be fixed by position
draw3 <- partial(sample, , 3)
draw3(letters)
# Use departial() to recover the original function
stopifnot(identical(departial(draw3), sample))
# Lazily evaluate argument values by default
# The value of 'n' is evaluated whenever rnd() is called.
rnd <- partial(runif, n = rpois(1, 5))
replicate(4, rnd(), simplify = FALSE) # variable length
# Eagerly evaluate argument values with unquoting (`!!`)
# The value of 'n' is fixed when 'rnd_eager' is created.
rnd_eager <- partial(runif, n = !!rpois(1, 5))
len <- length(rnd_eager())
reps <- replicate(4, rnd_eager(), simplify = FALSE) # constant length
stopifnot(all(vapply(reps, length, integer(1)) == len))
# Mix evaluation schemes by combining lazy evaluation with unquoting (`!!`)
# Here 'n' is lazily evaluated, while 'max' is eagerly evaluated.
rnd_mixed <- partial(runif, n = rpois(1, 5), max = !!sample(10, 1))
replicate(4, rnd_mixed(), simplify = FALSE)
# Arguments to fix can be spliced
args_eager <- list(n = rpois(1, 5), max = sample(10, 1))
rnd_eager2 <- partial(runif, !!!args_eager)
replicate(4, rnd_eager2(), simplify = FALSE)
# Use rlang::exprs() to selectively evaluate arguments to fix
args_mixed <- rlang::exprs(n = rpois(1, 5), max = !!sample(10, 1))
rnd_mixed2 <- partial(runif, !!!args_mixed)
replicate(4, rnd_mixed2(), simplify = FALSE)
# partial() truncates formals by the fixed arguments, omits default values
foo <- function(x, y = x, ..., z = "z") NULL
stopifnot(
identical(formals(partial(foo)),
formals(foo)),
identical(formals(partial(foo, x = 1)),
formals(function(y, ..., z) NULL)),
identical(formals(partial(foo, x = 1, y = 2)),
formals(function(..., z) NULL)),
identical(formals(partial(foo, x = 1, y = 2, z = 3)),
formals(function(...) NULL))
)
# Nevertheless, partial() remembers default argument values when called
f <- function(x, y = x) c(x, y)
p <- partial(f, x = 1)
stopifnot(identical(p(), c(1, 1)))