I'm currently in evironment hell. To make a long story short, I'm trying to write my own pipe. This is because I'm developing a package with some special objects and I want to write a pipe operator that could allow users to compose functions that compute over these special objects. (if you're interested, here's a blog post The {chronicler} package, an implementation of the logger monad in R)
Now my issue with the pipe I wrote is that it seems to work as long as I'm working interactively in the global env. If I call code that uses the pipe, user-defined functions don't get found. Here is a reproducible example. I have one script with the following code:
`%>=%` <- function(.x, .f, ...) {
parsed <- parse_function(deparse1(substitute(.f)))
cmd <- make_command(parsed)
eval(parse(text = cmd))
}
make_command <- function(parsed_function){
paste0(".x |> ",
parsed_function$func,
"(",
parsed_function$args, ")"
)
}
parse_function <- function(.f_string){
func <- gsub("\\(.*$", "", .f_string)
args <- stringr::str_extract(.f_string, "\\(.*")
args <- gsub("^\\(", "", args)
args <- gsub("\\)$", "", args)
args <- ifelse(args != "", paste0(args, ", "), "")
list("func" = func,
"args" = args)
}
This defines my pipe. Here some tests to see that it works:
a <- c(seq(1:10), NA)
my_log <- log
my_mean <- mean
a %>=%
my_mean(na.rm = TRUE) %>=%
my_log()
log(mean(a, na.rm = TRUE))
No problems here (it is important that I define my_log and my_mean, because that's how my package works, by defining new functions that will work with the pipe).
Now suppose I have a script with this content:
test_that("test equality", {
my_sqrt <- sqrt
my_exp <- exp
my_mean <- mean
result_pipe <- 1:10 %>=%
my_sqrt() %>=%
my_exp() %>=%
my_mean()
result <- my_mean(my_exp(my_sqrt(1:10)))
expect_equal(result_pipe, result)
})
Calling this script with testthat::test_file("test.R") errors with following message:
ββ Testing test.R βββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββββ
[ FAIL 1 | WARN 0 | SKIP 0 | PASS 0 ]
ββ Error (test.R:7:3): test equality βββββββββββββββββββββββββββββββββββββββββββ
Error in `my_exp(.x)`: could not find function "my_exp"
Backtrace:
1. 1:10 %>=% my_sqrt() %>=% my_exp() %>=% my_mean()
at test.R:7:2
5. 1:10 %>=% my_sqrt() %>=% my_exp()
[ FAIL 1 | WARN 0 | SKIP 0 | PASS 0 ]
my_exp
is not found (my_log and my_mean get found only if you run the main script first, so they're in the global env, but if you run in completely fresh session, then they won't get found either).
Thanks to some helpful people on twitter, I realised that the problem is due to environments. I tried some stuff, and tried googling around, tried using quosures etc, but nothing seems to work. Any help much appreciated.