unpipe - rewriting an expression without the pipes

Playing with rlang package - Removing the pipe operator

  • I’m trying to wrap my head around some parts of the rlang package so I set myself a task to focus my exploration: Auto-rewrite a chain of piped functions as a set of nested function calls

unpipe

#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# unpipe - rewrite a chain of piped functions as a set of nested function calls
#
# A recursive function that descends through the language tree and flips 
# arguments
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
unpipe <- function(ee) {
  if (!rlang::is_call(ee)) { 
    return(ee) 
  }
  
  this_fn <- rlang::call_name(ee)
  updated_args <- rlang::call_args(ee) %>% map(unpipe)
  
  if (identical(this_fn, "%>%")) {
    lhs <- updated_args[[1]]
    rhs <- updated_args[[2]]
    if (rlang::is_call(rhs)) {
      rlang::call2(call_name(rhs), !!!c(lhs, call_args(rhs)))
    } else {
      rlang::call2(rhs, lhs)
    }
  } else {
    rlang::call2(this_fn, !!!updated_args)
  }
}
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# Improbable test chain with a variety of lhs/rhs arguments to a pipe
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
chain <- quote(
  1:3 %>% 
    mean(na.rm=TRUE) %>% 
    print %>% 
    filter(hello == median(zz))
)


#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
# unpipe this chain
#~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
chain
1:3 %>% mean(na.rm = TRUE) %>% print %>% filter(hello == median(zz))
unpipe(chain)
filter(print(mean(1:3, na.rm = TRUE)), hello == median(zz))

Tweetable unpipe()

#rstats #unpipe
library(rlang)
U=function(ee){A=call_args;N=call_name;C=call2;I=is_call
if(!I(ee)){return(ee)}
f=N(ee)
u=purrr::map(A(ee),U)
if(f=="%>%"){l=u[[1]]
r=u[[2]]
if(I(r)){C(N(r),!!!c(l,A(r)))}else{C(r,l)}}else{C(f,!!!u)}}

U(quote(1:3 %>% mean(na.rm=TRUE) %>% print))
print(mean(1:3, na.rm = TRUE))