Closed orgadish closed 1 year ago
I think the sort of things you're trying to do is likely to be brittle and cause surprising behaviour in some cases (e.g. magrittr vs base pipe). I would not recommend metaprogramming here.
I don't really understand what you're trying to achieve. I'm imagining something like memoise::memoise(function(x) x |> foo())
but I'm not sure.
I'm closing this issue because it's meant for bugs and feature requests, but feel free to continue the discussion.
I didn't know about memoise::memoise
-- thanks! One of the main things I was trying to get with my cachedread
utility is that it determines whether to re-read the input files based on whether they have been modified since they were cached. Right now I do this with cached_read(files, read_fn)
where read_fn
can be, for example, readr::read_csv
, or an entire function pipeline \(.x) readr::read_csv(.x) |> janitor::clean_names()
, etc. so that the output of the whole pipeline is cached. To use this functionality at the end of the pipeline (e.g. readr::read_csv(.x) |> janitor::clean_names() |> cachedread::use_caching()
) with the checking of modified input files I have to be able to access that first element (files
).
Another use case I'm working on is a function that allows conversion of a dplyr
pipeline into dtplyr
just by adding a line at the end (rather than having to add lazy_dt
at the beginning and collect
at the end). This is because I often find myself wanting to test whether the code I'm running would be quicker with dtplyr
, so I want to test it quickly, or benchmark it. In these cases, I need access to the original df
so I can replace it with lazy_dt(df)
in the pipeline.
It would be great if there was an rlang::call_structure
, for example, which broke down a function call into a series of calls and then allowed metaprogramming on that.
Rerunning computations after a change in input resources seems like a good job for https://github.com/ropensci/targets
Unfortunately call_structure()
feels out of scope for rlang, sorry.
I have a couple scenarios where I want a function that takes in an R expression (pipeline), modifies the innermost (first) element and then runs the rest of the expression/pipeline. For example, I wrote a package
cachedread
which can take aread_csv(x) |> ...
pipeline and automatically read into a cache file for subsequent reads.The most straightforward way I've found to do this is to use functional programming and take the input and the rest of the function separately
my_function <- function(.x, .f) .f(modify_input(.x))
.However, it would be nice if the function could be added to the end of an existing pipeline, i.e. take the whole expression and parse out the first element from the rest.
I've hacked together a solution (below) by looping/recursing down using the expression using
rlang::call_fn
andrlang::call_args
, and then back up looping/recursing withrlang::call2
, but it feels like there are probably already existing rlang (or other) functions that do this better?