Skip to content

Extending partial() to comprehend quasiquotation #457

@egnha

Description

@egnha

It would be nice if partial() were augmented to comprehend quasiquotation, in a way that:

  • preserves the API—maintains the current behavior and argument signature
  • enables partialized arguments to be unquoted and spliced

(Additionally, in the degenerate case where no partialized arguments are supplied, partial() should simply apply as_mapper().)

One possibility is as follows:

library(nofrills)

partial <- function(...f, ..., .env = parent.frame(), .lazy = TRUE, .first = TRUE) {
  ...f <- as_mapper(...f)
  args <- if (.lazy) exprs(...) else lapply(quos(...), eval_tidy)
  
  if (is_empty(args))
    return(...f)
  
  env <- child_env(.env, ...f = ...f)
  if (.first)
    nofrills::fn(... ~ ...f(!!! args, ...), ..env = env)
  else
    nofrills::fn(... ~ ...f(..., !!! args), ..env = env)
}

Remarks:

Some examples showing quasiquotation and compatibility with the current behavior:

# Partialized arguments are lazily evaluated, by default
f <- partial(runif, n = rpois(1, 5))
f
#> function (...) 
#> ...f(n = rpois(1, 5), ...)
#> <environment: 0x10c5338d8>
f() #> [1] 0.5433265
f() #> [1] 0.9367817 0.7762598

# Eager evaluation by setting .lazy = FALSE
f <- partial(runif, n = rpois(1, 5), .lazy = FALSE)
f
#> function (...) 
#> ...f(n = 3L, ...)
#> <environment: 0x10c594ae0>
f() #> [1] 0.9508948 0.8669053 0.4992270
f() #> [1] 0.04073824 0.93821289 0.43544412

# Eager evaluation by unquoting
partial(runif, n = !! rpois(1, 5))
#> function (...) 
#> ...f(n = 4L, ...)
#> <environment: 0x10c5b5aa8>

# Arguments can be spliced eagerly
partial(runif, !!! list(n = rpois(1, 5), max = 2))
#> function (...) 
#> ...f(n = 3L, max = 2, ...)
#> <environment: 0x10c64ef48>
  
# Arguments can be spliced lazily
partial(runif, !!! quos(n = rpois(1, 5), max = 2))
#> function (...) 
#> ...f(n = rpois(1, 5), max = 2, ...)
#> <environment: 0x10c670e30>

(For now, I'm omitting a better print method to focus on the main point.)

Metadata

Metadata

Assignees

No one assigned

    Labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions