Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

debug a function when Safely from Purrr has been used?

Tags:

r

purrr

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')
like image 926
MLEN Avatar asked Dec 18 '25 19:12

MLEN


1 Answers

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.

like image 82
Allan Cameron Avatar answered Dec 20 '25 15:12

Allan Cameron



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!