Skip to content

Commit

Permalink
Deprecate lift_*
Browse files Browse the repository at this point in the history
Fixes #871
  • Loading branch information
hadley committed Aug 25, 2022
1 parent 0919f38 commit 0172fb6
Show file tree
Hide file tree
Showing 8 changed files with 110 additions and 119 deletions.
3 changes: 3 additions & 0 deletions NEWS.md
Expand Up @@ -8,6 +8,9 @@
no longer think they are the right approach to solving this problem.
See #768 for more information.

* The `lift_*` family of functions has been deprecated. We no longer believe
these to be a good fit for purrr because rely on a style of function
manipulation that is very uncommon in R code (#871).

## Features and fixes

Expand Down
88 changes: 32 additions & 56 deletions R/composition.R
@@ -1,5 +1,8 @@
#' Lift the domain of a function
#'
#' @description
#' `r lifecycle::badge("deprecated")`
#'
#' `lift_xy()` is a composition helper. It helps you compose
#' functions by lifting their domain from a kind of input to another
#' kind. The domain can be changed from and to a list (l), a vector
Expand All @@ -12,6 +15,10 @@
#' functional tools. Since this is such a common function,
#' `lift()` is provided as an alias for that operation.
#'
#' We have deprecated these functions because we no longer believe "lifting"
#' to be a mainstream operation, and we are striving to reduce purrr to its
#' most useful core.
#'
#' @inheritParams as_vector
#' @param ..f A function to lift.
#' @param ... Default arguments for `..f`. These will be
Expand Down Expand Up @@ -41,36 +48,26 @@ NULL
#'
#' x <- list(x = c(1:100, NA, 1000), na.rm = TRUE, trim = 0.9)
#' lift_dl(mean)(x)
#'
#' # Or in a pipe:
#' mean %>% lift_dl() %>% invoke(x)
#'
#' # You can also use the lift() alias for this common operation:
#' lift(mean)(x)
#' # now:
#' exec(mean, !!!x)
#'
#' # Default arguments can also be specified directly in lift_dl()
#' list(c(1:100, NA, 1000)) %>% lift_dl(mean, na.rm = TRUE)()
#' # now:
#' mean(c(1:100, NA, 1000), na.rm = TRUE)
#'
#' # lift_dl() and lift_ld() are inverse of each other.
#' # Here we transform sum() so that it takes a list
#' fun <- sum %>% lift_dl()
#' fun(list(3, NA, 4, na.rm = TRUE))
#'
#' # Now we transform it back to a variadic function
#' fun2 <- fun %>% lift_ld()
#' fun2(3, NA, 4, na.rm = TRUE)
#'
#' # It can sometimes be useful to make sure the lifted function's
#' # signature has no named parameters, as would be the case for a
#' # function taking only dots. The lifted function will take a list
#' # or vector but will not match its arguments to the names of the
#' # input. For instance, if you give a data frame as input to your
#' # lifted function, the names of the columns are probably not
#' # related to the function signature and should be discarded.
#' lifted_identical <- lift_dl(identical, .unnamed = TRUE)
#' mtcars[c(1, 1)] %>% lifted_identical()
#' mtcars[c(1, 2)] %>% lifted_identical()
#' # now:
#' fun <- function(x) exec("sum", !!!x)
#' exec(sum, 3, NA, 4, na.rm = TRUE)
lift <- function(..f, ..., .unnamed = FALSE) {
lifecycle::deprecate_warn("0.4.0", "lift()")

force(..f)
defaults <- list(...)
function(.x = list(), ...) {
Expand All @@ -88,6 +85,8 @@ lift_dl <- lift
#' @rdname lift
#' @export
lift_dv <- function(..f, ..., .unnamed = FALSE) {
lifecycle::deprecate_warn("0.4.0", "lift_dv()")

force(..f)
defaults <- list(...)

Expand All @@ -111,21 +110,17 @@ lift_dv <- function(..f, ..., .unnamed = FALSE) {
#' type by supplying `.type`.
#' @export
#' @examples
#' #
#'
#'
#' ### Lifting from c(...) to list(...) or ...
#'
#' # In other situations we need the vector-valued function to take a
#' # variable number of arguments as with pmap(). This is a job for
#' # lift_vd():
#' pmap(mtcars, lift_vd(mean))
#'
#' # lift_vd() will collect the arguments and concatenate them to a
#' # vector before passing them to ..f. You can add a check to assert
#' # the type of vector you expect:
#' lift_vd(tolower, .type = character(1))("this", "is", "ok")
#' pmap_dbl(mtcars, lift_vd(mean))
#' # now
#' pmap_dbl(mtcars, ~ mean(c(...)))
lift_vl <- function(..f, ..., .type) {
lifecycle::deprecate_warn("0.4.0", "lift_vl()")

force(..f)
defaults <- list(...)
if (missing(.type)) .type <- NULL
Expand All @@ -139,6 +134,8 @@ lift_vl <- function(..f, ..., .type) {
#' @rdname lift
#' @export
lift_vd <- function(..f, ..., .type) {
lifecycle::deprecate_warn("0.4.0", "lift_vd()")

force(..f)
defaults <- list(...)
if (missing(.type)) .type <- NULL
Expand All @@ -162,43 +159,20 @@ lift_vd <- function(..f, ..., .type) {
#'
#' @export
#' @examples
#' #
#'
#'
#' ### Lifting from list(...) to c(...) or ...
#'
#' # cross() normally takes a list of elements and returns their
#' # cartesian product. By lifting it you can supply the arguments as
#' # if it was a function taking dots:
#' cross_dots <- lift_ld(cross)
#' out1 <- cross(list(a = 1:2, b = c("a", "b", "c")))
#' out2 <- cross_dots(a = 1:2, b = c("a", "b", "c"))
#' identical(out1, out2)
#'
#' # This kind of lifting is sometimes needed for function
#' # composition. An example would be to use pmap() with a function
#' # that takes a list. In the following, we use some() on each row of
#' # a data frame to check they each contain at least one element
#' # satisfying a condition:
#' mtcars %>% pmap(lift_ld(some, partial(`<`, 200)))
#'
#' # Default arguments for ..f can be specified in the call to
#' # lift_ld()
#' lift_ld(cross, .filter = `==`)(1:3, 1:3) %>% str()
#' mtcars %>% pmap_lgl(lift_ld(some, partial(`<`, 200)))
#' # now
#' mtcars %>% pmap_lgl(~ any(c(...) > 200))
#'
#'
#' # Here is another function taking a list and that we can update to
#' # take a vector:
#' glue <- function(l) {
#' if (!is.list(l)) stop("not a list")
#' l %>% invoke(paste, .)
#' }
#'
#' \dontrun{
#' letters %>% glue() # fails because glue() expects a list}
#'
#' letters %>% lift_lv(glue)() # succeeds
lift_ld <- function(..f, ...) {
lifecycle::deprecate_warn("0.4.0", "lift_ld()")

force(..f)
defaults <- list(...)
function(...) {
Expand All @@ -209,6 +183,8 @@ lift_ld <- function(..f, ...) {
#' @rdname lift
#' @export
lift_lv <- function(..f, ...) {
lifecycle::deprecate_warn("0.4.0", "lift_lv()")

force(..f)
defaults <- list(...)
function(.x, ...) {
Expand Down
2 changes: 1 addition & 1 deletion R/cross.R
Expand Up @@ -19,7 +19,7 @@
#' )
#'
#' # With deprecated `cross()`
#' data %>% cross() %>% map_chr(lift(paste))
#' data %>% cross() %>% map_chr(~ paste(..., collapse = " "))
#'
#' # With `expand_grid()`
#' tidyr::expand_grid(!!!data) %>% pmap_chr(paste)
Expand Down
1 change: 0 additions & 1 deletion _pkgdown.yml
Expand Up @@ -95,7 +95,6 @@ reference:
contents:
- faq-adverbs-export
- compose
- lift
- negate
- partial
- safely
Expand Down
7 changes: 4 additions & 3 deletions man/cross.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

78 changes: 20 additions & 58 deletions man/lift.Rd

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

33 changes: 33 additions & 0 deletions tests/testthat/_snaps/composition.md
@@ -0,0 +1,33 @@
# lift_* is deprecated

Code
. <- lift(mean)
Condition
Warning:
`lift()` was deprecated in purrr 0.4.0.
Code
. <- lift_dv(mean)
Condition
Warning:
`lift_dv()` was deprecated in purrr 0.4.0.
Code
. <- lift_vl(mean)
Condition
Warning:
`lift_vl()` was deprecated in purrr 0.4.0.
Code
. <- lift_vd(mean)
Condition
Warning:
`lift_vd()` was deprecated in purrr 0.4.0.
Code
. <- lift_ld(mean)
Condition
Warning:
`lift_ld()` was deprecated in purrr 0.4.0.
Code
. <- lift_lv(mean)
Condition
Warning:
`lift_lv()` was deprecated in purrr 0.4.0.

0 comments on commit 0172fb6

Please sign in to comment.