Lazily evaluate named interpolation variables#83
Closed
egnha wants to merge 6 commits into
Closed
Conversation
Contributor
Author
|
f5c7d14 is a much faster and more concise way to lazily bind interpolation arguments. Here are the three ways of binding interpolation variables: # Faster, functionally equivalent version of 'bind_ordered_promises()'
bind_promises <- function(args, parent) {
promises <- as_promises(args)
parent.env(promises) <- parent
promises
}
as_promises <- function(args) {
eval(call("function", as.pairlist(args), quote(environment())))()
}
# da715b81676d66df5c07abc1df98566292686be0
bind_ordered_promises <- function(args, parent) {
env_assign <- parent
for (nm in names(args)) {
env_eval <- env_assign
env_assign <- new.env(parent = env_assign)
eval(bquote(delayedAssign(nm, .(args[[nm]]), env_eval, env_assign)))
}
env_assign
}
# Eager evaluation (current master)
assign_args <- function(args, envir) {
# I've disabled the following orphaned assignment, probably a refactoring oversight
# res <- vector("list", length(args))
nms <- names(args)
for (i in seq_along(args)) {
assign(nms[[i]], eval(args[[i]], envir), envir = envir)
}
}Here's how they stack up: parent <- environment()
envir <- new.env()
x <- "x"; y <- "y"; z <- "z"
args <- alist(x = x, y = y, z = z)
microbenchmark::microbenchmark(
bind_promises(args, parent),
bind_ordered_promises(args, parent),
assign_args(args, envir),
times = 1e5
)
#> Unit: microseconds
#> expr min lq mean median uq max neval
#> bind_promises(args, parent) 3.218 4.382 5.882061 4.923 5.393 58631.224 1e+05
#> bind_ordered_promises(args, parent) 38.783 46.881 54.960408 50.372 53.852 44366.326 1e+05
#> assign_args(args, envir) 6.192 8.048 9.406942 8.723 9.420 3496.235 1e+05
|
Contributor
Author
|
d21268e corrects an oversight: lazy scoping should occur from left to right to preserve the existing API. Additional test cases added. Thus bind_promises <- function(args, parent) {
env <- env_init <- new.env(parent = baseenv())
for (i in seq_along(args))
env <- as_promise(.subset(args, i), env)
parent.env(env_init) <- parent
env
}
as_promise <- function(arg, env) {
make_promise <- as.call(c(
call("function", as.pairlist(arg), quote(environment())),
arg
))
eval(make_promise, env)
}The complexity of parent <- environment()
envir <- new.env()
x <- "x"; y <- "y"; z <- "z"
args <- alist(x = x, y = y, z = z)
microbenchmark::microbenchmark(
bind_promises(args, parent),
bind_ordered_promises(args, parent),
assign_args(args, envir),
times = 1e5
)
#> Unit: microseconds
#> expr min lq mean median uq max neval
#> bind_promises(args, parent) 11.624 15.196 18.499932 16.453 17.8200 66063.555 1e+05
#> bind_ordered_promises(args, parent) 38.426 47.695 56.625133 50.986 54.8820 64272.838 1e+05
#> assign_args(args, envir) 6.196 8.128 10.018293 8.825 9.5590 56623.842 1e+05 |
Collaborator
|
Thanks! I ended up using |
Contributor
Author
|
Great, thanks! |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
A priori, an interpolation string need not reference every variable supplied as a named dot-argument of
glue_data(), so there is no need to evaluate them eagerly. In particular,glue("{x}", x = "blah", y = {Sys.sleep(1); "y"})ought to be as fast asglue("{x}", x = "blah"), andglue("blah", x = stop("!"))should also yieldas_glue("blah").This PR implements (ordered) lazy evaluation of named interpolation variables.
If this is desirable, a review would be appreciated.
Thanks for your consideration.