I have a function that has been saved as an Rds object and I'm wondering if there is any possibility after reading the function to debug() it or to see the code inside the function?
Example
library(purrr)
some_function <- function(x){
avg <- mean(x)
std <- sd(x)
return(c(avg, std))
}
safe_function <- safely(some_function)
saveRDS(safe_function, 'safe_function.rds')
rm(safe_function)
# How can I debug the function or make changes to it after I've loaded it?
safe_function <- readRDS('safe_function.rds')
The short answer is that it's easy to extract the underlying function, with a single line of code:
extracted_function <- environment(safe_function)$.f
extracted_function
#> function(x){
#>
#>
#> avg <- mean(x)
#> std <- sd(x)
#>
#> return(c(avg, std))
#>
#> }
#> <bytecode: 0x1951c3e0>
You can debug this function however you like, then if you want to overwrite it but keep it within its safely wrapper, you can overwrite it like this:
debugged_function <- function(x) c(mean(x, na.rm = TRUE), sd(x, na.rm = TRUE))
environment(safe_function)$.f <- debugged_function
safe_function(1:10)
#> $result
#> [1] 5.50000 3.02765
#>
#> $error
#> NULL
I'll give a quick explanation of why this works:
If you examine your safe_function, you will notice a couple of unusual things about it. Although you have loaded it into the global environment, it is actually wrapped in its own unnamed environment (in this case <environment: 0x095704c0>), which is integral to the way that it works:
safe_function
#> function (...)
#> capture_error(.f(...), otherwise, quiet)
#> <bytecode: 0x0956fd50>
#> <environment: 0x095704c0>
The other odd thing you'll notice is that safe_function calls the function .f, which is neither a built-in function, nor a function exported from purrr. That's because .f is a copy of your original function that is kept inside this special environment.
We can look at the complete contents of the unnamed environment by doing:
ls(environment(safe_function), all.names = TRUE)
#> [1] ".f" "otherwise" "quiet"
Now, if you look at what .f is, you will find it is just a copy of your original some_function:
#> function(x){
#>
#>
#> avg <- mean(x)
#> std <- sd(x)
#>
#> return(c(avg, std))
#>
#> }
#> <bytecode: 0x1951c3e0>
So this is where your wrapped function is "hiding". It remains accessible as a member of this unnamed environment, which can be accessed via environment(safe_function) so is easy to modify if desired.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With