WinVector / wrapr

Wrap R for Sweet R Code
https://winvector.github.io/wrapr/
Other
136 stars 11 forks source link

Feature Request: wrapr::let map a name to something 'other than a name.' #2

Closed AndreMikulec closed 7 years ago

AndreMikulec commented 7 years ago

If the 'methods of' mapping from desired names to names used in the data were liberalized, then this liberalization would be very useful. For for example, a name could map to 'other than a name.'

# sessionInfo() # [1] wrapr_0.2.0
let( alias=list(SORT_COLUMNS = "cyl"), { 
  head(plyr::arrange(mtcars, SORT_COLUMNS)) }, 
subsMethod = 'stringsubs') 
   mpg cyl  disp hp drat    wt  qsec vs am gear carb
1 22.8   4 108.0 93 3.85 2.320 18.61  1  1    4    1
2 24.4   4 146.7 62 3.69 3.190 20.00  1  0    4    2
3 22.8   4 140.8 95 3.92 3.150 22.90  1  0    4    2
4 32.4   4  78.7 66 4.08 2.200 19.47  1  1    4    1
5 30.4   4  75.7 52 4.93 1.615 18.52  1  1    4    2
6 33.9   4  71.1 65 4.22 1.835 19.90  1  1    4    1
let( alias=list(SORT_COLUMNS = "cyl, disp"), {  
  head(plyr::arrange(mtcars, SORT_COLUMNS )) }
, subsMethod = 'stringsubs') 

Error in prepareAlias(alias) :
  wrapr:let alias value not a valid name: " cyl, disp "
eval(parse(text=stringr::str_interp("

  require(magrittr)
  head(plyr::arrange(mtcars, ${SORT_COLUMNS} )) %>%
  print

", list(SORT_COLUMNS = "cyl, disp"))))

WORKS

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
2 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
3 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
4 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
5 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
6 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
LET <- function(alias = NULL, string_expr = NULL) {
  eval(parse(text=stringr::str_interp(string = string_expr, env = alias)))
}
LET(alias = list(SORT_COLUMNS = "cyl, disp")
  , string_expr = "head(plyr::arrange(mtcars, ${SORT_COLUMNS} ))"  
)

WORKS

Without the hard-coded data.frame mtcars Good enough for piping

LETP <- function(payload = NULL, alias = NULL, string_expr = NULL) {
  x <- payload
  eval(parse(text=stringr::str_interp(string = string_expr, env = alias)))
}

library(magrittr)

mtcars %>%
 { LETP(payload = .
, alias = list(SORT_COLUMNS = "cyl, disp")
, string_expr = "head(plyr::arrange(x, ${SORT_COLUMNS} ))"  ) }

WORKS

shortest working way to write

mtcars %>% LETP(., list(SORT_COLUMNS = "cyl, disp"), "head(plyr::arrange(x, ${SORT_COLUMNS} ))")  

WORKS

   mpg cyl  disp  hp drat    wt  qsec vs am gear carb
1 33.9   4  71.1  65 4.22 1.835 19.90  1  1    4    1
2 30.4   4  75.7  52 4.93 1.615 18.52  1  1    4    2
3 32.4   4  78.7  66 4.08 2.200 19.47  1  1    4    1
4 27.3   4  79.0  66 4.08 1.935 18.90  1  1    4    1
5 30.4   4  95.1 113 3.77 1.513 16.90  1  1    5    2
6 22.8   4 108.0  93 3.85 2.320 18.61  1  1    4    1
JohnMount commented 7 years ago

AndreMikulec,

Thanks for your input and examples. The free-subsitution is pretty far away from the intent of let, but fairly close to the behavior of beval and ateval. So I am adding a new function (now available in the development version) with behavior close to what you describe as seval (now in the development version of wrapr).

The following all works:

seval( alias=list(SORT_COLUMNS = "cyl, disp"), {  
  head(dplyr::arrange(mtcars, SORT_COLUMNS )) 
})

seval( alias=list(SORT_COLUMNS = "cyl, disp"), {  
  mtcars %>% dplyr::arrange(SORT_COLUMNS) %>% head
})

mtcars %>% (function(x) {
  seval( alias=list(SORT_COLUMNS = "cyl, disp"), {  
    x %>% dplyr::arrange(SORT_COLUMNS) %>% head
  })
})

As far as direct piping forms (such as letp and a possible sevalp). I used to have a letp() in replyr as replyr declares dplyr (and hence magrittr pipe) as a dependency). But I never liked the solution needed to get around the function wrapping needed in the the 3rd of the above examples. It really looked like it would be a problem to maintain going forward. I just don't have generic solution for the direct piping adapter that will meet certain standards. So I have (unfortunately) much given up on try to safely supply the p-"ready to pipe" forms, that is being left to user code.

Hopefully that is close to your ask. I know it doesn't completely match- but my intent is to keep let itself very strict so it is very early to reason about. The more general submitters are beval, ateval, and seval. And finally I have been asked by others to keep wrapr an R-only dependency free package that can be used both with or without the tidyverse (so it can't declare a dplyr, magritter, stringr, or stringi dependency).

AndreMikulec commented 7 years ago

Thanks.