knitr::opts_chunk$set( collapse = TRUE, comment = "#>", fig.path = "README-" ) library(curry) Sys.setenv(LANG = "en")
curry
is yet another attempt at providing a native currying/partial
application mechanism in R. Other examples of implementations of this can be
found in purrr
and
functional
(and probably
others). curry
sets itself apart in the manner it is used and in the functions
it creates. curry
is operator based and a partially applied function retains
named arguments for easier autocomplete etc. curry
provides three mechanisms
for partial application: %<%
(curry()
), %-<%
(tail_curry()
), and %><%
(partial()
) - see the examples for the differences
Currying is the reduction of the arity of a function by fixing the first argument, returning a new function lacking this.
# Equivalent to curry(`+`, 5) add_5 <- `+` %<% 5 add_5(10) # ellipsis are retained when currying bind_5 <- cbind %<% 5 bind_5(1:10)
Tail currying is just like currying except it reduces the arity of the function from the other end by fixing the last argument.
# Equivalent to tail_curry(`/`, 5) divide_by_5 <- `/` %-<% 5 divide_by_5(10) no_factors <- data.frame %-<% FALSE df <- no_factors(x = letters[1:5]) class(df$x)
When the argument you wish to fix is not in either end of the argument list it
is necessary to use a more generalised approach. Using %><%
(or partial()
)
it is possible to fix any (and multiple) arguments in a function using a list of
values to fix.
dummy_lengths <- vapply %><% list(FUN = length, FUN.VALUE = integer(1)) test_list <- list(a = 1:5, b = 1:10) dummy_lengths(test_list)
Other efforts in this has the drawback of returning a new function with just an
ellipsis, making argument checks and autocomplete impossible. With curry
the
returned functions retains named arguments (minus the fixed ones).
args(no_factors) args(dummy_lengths)
The above uses a very loose (incorrect) definition of currying. The correct definition is that currying a function returns a function taking a single argument (the first from the original function). Calling a curried function will return a new function accepting the second argument of the original function and so on. Once all arguments of the original function has been consumed it evaluates the call and returns the result. Thus:
# Correct currying foo(arg1)(arg2)(arg3) # Incorrect currying foo(arg1)(arg2, arg3)
True currying is less useful in R as it does not play nice with function
containing ...
as the argument list will never be consumed. Still, it is
available in curry
using the Curry()
function or the %<!%
operator:
testfun <- function(x = 10, y, z) { x + y + z } curriedfun <- Curry(testfun) curriedfun(1)(2)(3) # Using the operator testfun %<!% 1 %<!% 2 %<!% 3 # The strict operator is only required for the first call testfun %<!% 1 %<% 2 %<% 3
As with the partial application functionality the strict currying retains argument names and defaults at each step of the currying sequence:
args(curriedfun)
The last functionality provided by curry
is a "weak" partial function
application in the sense that it sets (or changes) argument defaults. Thus,
compared to partial application it returns a function with the same arguments,
but if the defaulted arguments are ignored it will be equivalent to a partial
application. Defaults can be set or changed using the set_defaults()
function
or the %<?%
operator:
testfun <- function(x = 1, y = 2, z = 3) { x + y + z } testfun() testfun2 <- testfun %<?% list(y = 10) testfun3 <- testfun %><% list(y = 10) testfun2() testfun3() testfun2(y = 20) testfun3(y = 20)
curry
can be installed from CRAN:
install.packages('curry')
or GitHub for the latest version:
if (!require(devtools)) { install.packages(devtools) } devtools::install_github('thomasp85/curry')
Add the following code to your website.
For more information on customizing the embed code, read Embedding Snippets.