-
Notifications
You must be signed in to change notification settings - Fork 129
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Incorporate rlang tidy evaluation in drake #200
Comments
This could even help with @AlexAxthelm's #77 and #79, which are I expect reimplementing
|
On the other hand, changing how commands are evaluated in A major strength of the current |
This is certainly a big move and you would probably want it on it's own branch to start. I am not so concerned about code running differently from the console vs in make as the use of this feature is really just for power users who would be able to navigate fine. The nse interface in rlang is so particular that no one would put that in inadvertently. One thing I've found a couple of times is that I want to create commands that depend on targets. For example, a regression command depends on the names of an intermediate dataset that only exists as a target. I workaround this by calling make twice. Once after the intermediate dataset is built. tidy evaluation might allow users to overcome these awkward workarounds with slightly less awkward workarounds. |
Yeah, I guess tidy evaluation does not totally overturn evaluation itself. And if the code in actual commands could depend on the values of previous targets, #77 would have a lot more potential. |
Begins to address #200. Tries to support the !! operator and quosures.
From this blog, it should be enough to replace my use of formatR::tidy_source(text = "!!little_b", output = FALSE)$text.tidy
## [1] "!(!little_b)" Is there a pre-packaged equivalent that is more tidyverse-compliant? |
Tidying commands is important because that's how For maximum compatibility and increased safety all around, here is what I am thinking: the command that is reformatted with
|
Another setback: non-lexical scoping in tidy eval: my_plan <- drake_plan(list = c(
little_b = "\"b\"",
letter = "!!little_b"
))
make(my_plan, envir = new.env(parent = globalenv()))
## fail letter
diagnose(letter)
## [1] "object 'little_b' not found" |
On the plus side, the following works in d8431e0 since all the environments agree. We're close. my_plan <- drake_plan(list = c(
little_b = "\"b\"",
letter = "!!little_b"
))
make(my_plan)
readd(letter)
## [1] "b" Now, is there a way to force a quasiquotation to use old-fashioned lexical scoping? |
What we really need is a way to decide the environment where quasiquotation symbols are resolved. See this post. |
Quasiquotation with !! is enabled in commands, etc. Supports #200.
ccd967c seems to work for all parallel computing options currently implemented. Confirmation: install.packages("drake", type = "source", repos = NULL)
devtools::load_all("drake")
for(s in testing_scenario_names()){ # parallel computing and global/custom environment scenarios
set_testing_scenario(s)
print(get_testing_scenario())
test_with_dir("make() does tidy eval in commands", {
con <- dbug()
con$plan <- drake_plan(list = c(
little_b = "\"b\"",
letter = "!!little_b"
))
con$targets <- con$plan$target
testrun(con)
expect_equal(readd(letter), "b")
})
} Now, |
@kendonB if |
From this discussion, the only option may be to evaluate |
I'm curious about the use case here. It seems that the goal here is to use a evaluate an object while creating a plan, so that plans can be altered dynamically, but isn't that the domain of library("drake")
little_b <- "b"
letter_template <- drake_plan(
letter = letter__
)
letter_plan <- evaluate_plan(
letter_template,
rules = list(letter__ = little_b)
)
letter_plan
# target command
#1 letter_b b I agree that being tidy-friendly is a good thing, but I worry about what to do if I want to do if I want to delay evaluation of a variable until drake_plan(foo = bar %>% summarize(baz = mean(rlang::UQ(as.name("baz"))) in order for drake to not identify |
Since you brought that up, I am planning to go ahead and use tidy evaluation in |
Support tidy evaluation (solve #200)
Closed via #202. Thanks @kendonB and @AlexAxthelm! |
Coming back to this now. As far as I can see, there is still no way to delay tidy evaluation until the making stage? The use case of constructing commands that depend on the values of targets is then still unavailable in drake? |
Seems so. I have proposed some ideas in #233. |
It seems worthwhile to incorporate concepts from tidy evaluation there. |
I agree that like so many other library(drake)
plan <- drake_plan(list = c(index = "sample.int(26, 1)", letter = "LETTERS[!!index]"))
make(plan)
#> cache /tmp/Rtmp4BtHQk/.drake
#> connect 1 import: plan
#> connect 2 targets: index, letter
#> check 2 items: LETTERS, sample.int
#> check 1 item: index
#> target index
#> check 1 item: letter
#> target letter
readd(letter)
#> cache /tmp/Rtmp4BtHQk/.drake
#> [1] "L" |
nb: I have a stopgap workaround that sort of works for me, but it involves calling I use one plan to generate the data and create the levels for my splits, and then another to evaluate those levels. It loses the explicit dependency between the data source and the final analysis, but for something where there are changing levels, or the levels aren't known prior to runtime, I haven't found anything better in the current paradigm. An example: library("drake")
library("dplyr")
write.csv(iris, "iris.csv")
data_and_levels <- drake_plan(strings_in_dots = "literals",
data = read.csv(file_in("iris.csv")),
species_list = data %>% pull("Species") %>% unique()
)
make(data_and_levels)
loadd(species_list)
process_data_template <- drake_plan(strings_in_dots = "literals",
species_data = dplyr::filter(data, Species == "XXSPECIES"),
species_analysis = lm(
formula = Sepal.Length ~ Sepal.Width + Petal.Length,
data =species_data_XXSPECIES
)
)
process_data <- evaluate_plan(
plan = process_data_template,
rules = list(XXSPECIES = species_list)
)
second_plan <- process_data %>%
bind_rows(gather_plan(., target = "end"))
vis_drake_graph(drake_config(second_plan))
make(second_plan)
|
Ref: https://cran.r-project.org/web/packages/rlang/vignettes/tidy-evaluation.html
The
!!
operator would be especially useful when building up complicated commands.This, for example, works in tibble, which is my current workaround:
Using
tibble
in the background might be a good way to achieve this without much pain.The text was updated successfully, but these errors were encountered: