Home > other >  How to access variable from the parent function in R
How to access variable from the parent function in R

Time:04-23

I'm interested in an elegant way of using immutable variables from parent functions.

Let's see an example.

I have the dataframe with number of the week and its corresponding value.

df <- tribble(
  ~week, ~count,
  1, 99.6,
  2, 116, 
  3, 107, 
  4, 125, 
  5, 126, 
  6, 131, 
  7, 149, 
  8, 130, 
  9, 111,
  48, 43.4,
  49, 136, 
  50, 133,
  51, 115, 
  52, 93.3
  )

The following functions add to the dataframe columns with the first and the last date of every week.

  add_week_limit_dates <- function(df){
    year_change <- ifelse(any(df$week < 25) && any(df$week > 38), TRUE, FALSE)
    df %>% 
      mutate(week_start = week_to_date(week, 1, year_change),
             week_end = week_to_date(week, 7, year_change))
  }
  
  week_to_date <- function(week, day_of_week, year_change){
    paste0(get_year(week, year_change), 
           "-W", ifelse(week < 10, paste0("0", as.character(week)), week), 
           "-", day_of_week) %>% ISOweek2date()
  }
  
  get_year <- function(week, year_change){
    if(isTRUE(year_change)){
      ifelse(week < 38, year(Sys.Date()), year(Sys.Date()) - 1)
    } else{
      year(Sys.Date())
    }
  }
> add_week_limit_dates(df)
# A tibble: 14 × 4
    week count week_start week_end  
   <dbl> <dbl> <date>     <date>    
 1     1  99.6 2022-01-03 2022-01-09
 2     2 116.  2022-01-10 2022-01-16
 3     3 107.  2022-01-17 2022-01-23
 4     4 125.  2022-01-24 2022-01-30
 5     5 126.  2022-01-31 2022-02-06
 6     6 131.  2022-02-07 2022-02-13
 7     7 149.  2022-02-14 2022-02-20
 8     8 130.  2022-02-21 2022-02-27
 9     9 111.  2022-02-28 2022-03-06
10    48 43.4  2021-11-29 2021-12-05
11    49 136.  2021-12-06 2021-12-12
12    50 133.  2021-12-13 2021-12-19
13    51 115.  2021-12-20 2021-12-26
14    52 93.3  2021-12-27 2022-01-02

So, my question: is it possible not to set explicitly the common variable year_change and force the children function search for it in the parent one? I dream about the next way

df %>% 
  mutate(week_start = week_to_date(week, 1),
         week_end = week_to_date(week, 7))

UPD - Solution

As recommended I accessed the parent.frame(), but notice that it isn't expected one when you use it inside dplyr's methods

 add_week_limit_dates <- function(df){
    year_change <- ifelse(any(df$week < 25) && any(df$week > 38), TRUE, FALSE)
    df$week_start <- week_to_date(df$week, 1)
    df$week_end <- week_to_date(df$week, 7)
    df
  }
  
  week_to_date <- function(week, day_of_week){
    paste0(get_year(week, parent.frame()$year_change), 
           "-W", ifelse(week < 10, paste0("0", as.character(week)), week), 
           "-", day_of_week) %>% ISOweek2date()
  }
  
...

CodePudding user response:

you can access the scope of the calling function through the called function's parent frame:

mother <- function(){
  year_change = 8
  child()
}

child <- function(){
  print(parent.frame()$year_change)
}

... or define them in one of the function's immediate parent environments:

mother <- function(){ ## now the immediate parent environment
  year_change = 8
  child <- function(){
    print(year_change)
  }
  child()
}

... or in the global environment:

year_change = 8 ## the global environment

mother <- function(){
  print(paste("mom's idea of year_change is:", year_change))
  child <- function(){
    print(paste("kid's idea of year_change is:", year_change))
  }
  child()
}


Note that the immediate parent environment outmatches the farther ancestors if variables have the same name.

Details of scoping e.g. in H. Wickham: Advanced R


Edit

Shamefully forgot the possibility to pass variables through by taking advantage of the ellipsis ... argument.

example

mother_says <- function(...){
    tell_child(...)
}

tell_child <- function(...){
    args <- list(...)
    print(paste("Mom says:", args$message_to_daughter))
    tell_grandchild(...)
}

tell_grandchild <- function(...){
    args <- list(...)
    print(paste("Granny says:", args$message_to_grandchild))
}

example's output:

## > mother_says(message_to_daughter = "Hi, daughter, how're you?",
##          message_to_grandchild = "Grandchild, sweetie!"
##          )
##
## [1] "Mom says: Hi, daughter, how're you?"
## [1] "Granny says: Grandchild, sweetie!"

  •  Tags:  
  • r
  • Related