grapes

William Michael Landau

2017-04-01

In some computing subcultures, the term “grapes” refers to the percent sign, which R uses to name binary operators such as %*%. Here, grapes is an R package that turns arbitrary functions into binary operators. As with the magrittr pipe, this allows you to avoid cumbersome parentheses in your code.

library(grapes)
grow(rbind, c, from = "base") # Use `from` to specify a package or environment to search.
bunch()
## [1] "%c%"     "%rbind%"
nrow(sleep) 
## [1] 20
longer = sleep %rbind% sleep %rbind% sleep
nrow(longer)
## [1] 60
1 %rbind% 2 %c% 3
## [1] 1 2 3

In your workspace, you can define your own functions for your operators. That way, there is no need to set the from argument to tell grow() where to look.

myop <- function(x, y){
  1/x + 1/y
}
grow(myop)
2 %myop% 3
## [1] 0.8333333

Use bunch() and functions() to list the available operators and non-operator functions.

bunch()
## [1] "%c%"     "%myop%"  "%rbind%"
functions()
## [1] "myop"

Operators are left-associative!

2 %myop% 3 %myop% 4
## [1] 1.45
(2 %myop% 3) %myop% 4
## [1] 1.45
2 %myop% (3 %myop% 4)
## [1] 2.214286

You can even turn all available functions from a package or environment into operators. But be warned: there is no guarantee that these operators will actually work.

functions("knitr")
## Loading required package: knitr
##  [1] "Sweave2knitr"       "all_labels"         "all_rcpp_labels"   
##  [4] "asis_output"        "clean_cache"        "combine_words"     
##  [7] "current_input"      "dep_auto"           "dep_prev"          
## [10] "engine_output"      "extract_raw_output" "fig_chunk"         
## [13] "fig_path"           "hook_ffmpeg_html"   "hook_movecode"     
## [16] "hook_optipng"       "hook_pdfcrop"       "hook_plot_asciidoc"
## [19] "hook_plot_custom"   "hook_plot_html"     "hook_plot_md"      
## [22] "hook_plot_rst"      "hook_plot_tex"      "hook_plot_textile" 
## [25] "hook_purl"          "hook_r2swf"         "hook_scianimator"  
## [28] "image_uri"          "imgur_upload"       "include_app"       
## [31] "include_graphics"   "include_url"        "inline_expr"       
## [34] "kable"              "knit"               "knit2html"         
## [37] "knit2pdf"           "knit2wp"            "knit_child"        
## [40] "knit_exit"          "knit_expand"        "knit_filter"       
## [43] "knit_global"        "knit_meta"          "knit_meta_add"     
## [46] "knit_params"        "knit_params_yaml"   "knit_print"        
## [49] "knit_rd"            "knit_rd_all"        "knit_watch"        
## [52] "load_cache"         "normal_print"       "pandoc"            
## [55] "pat_asciidoc"       "pat_brew"           "pat_html"          
## [58] "pat_md"             "pat_rnw"            "pat_rst"           
## [61] "pat_tex"            "pat_textile"        "plot_crop"         
## [64] "purl"               "raw_output"         "read_chunk"        
## [67] "read_demo"          "read_rforge"        "render_asciidoc"   
## [70] "render_html"        "render_jekyll"      "render_latex"      
## [73] "render_listings"    "render_markdown"    "render_rst"        
## [76] "render_sweave"      "render_textile"     "restore_raw_output"
## [79] "rocco"              "rst2pdf"            "set_alias"         
## [82] "set_header"         "set_parent"         "spin"              
## [85] "spin_child"         "stitch"             "stitch_rhtml"      
## [88] "stitch_rmd"         "wrap_rmd"           "write_bib"
bunch("knitr")
## character(0)
grow(from = "knitr")
bunch()
##  [1] "%Sweave2knitr%"       "%all_labels%"         "%all_rcpp_labels%"   
##  [4] "%asis_output%"        "%c%"                  "%clean_cache%"       
##  [7] "%combine_words%"      "%current_input%"      "%dep_auto%"          
## [10] "%dep_prev%"           "%engine_output%"      "%extract_raw_output%"
## [13] "%fig_chunk%"          "%fig_path%"           "%hook_ffmpeg_html%"  
## [16] "%hook_movecode%"      "%hook_optipng%"       "%hook_pdfcrop%"      
## [19] "%hook_plot_asciidoc%" "%hook_plot_custom%"   "%hook_plot_html%"    
## [22] "%hook_plot_md%"       "%hook_plot_rst%"      "%hook_plot_tex%"     
## [25] "%hook_plot_textile%"  "%hook_purl%"          "%hook_r2swf%"        
## [28] "%hook_scianimator%"   "%image_uri%"          "%imgur_upload%"      
## [31] "%include_app%"        "%include_graphics%"   "%include_url%"       
## [34] "%inline_expr%"        "%kable%"              "%knit%"              
## [37] "%knit2html%"          "%knit2pdf%"           "%knit2wp%"           
## [40] "%knit_child%"         "%knit_exit%"          "%knit_expand%"       
## [43] "%knit_filter%"        "%knit_global%"        "%knit_meta%"         
## [46] "%knit_meta_add%"      "%knit_params%"        "%knit_params_yaml%"  
## [49] "%knit_print%"         "%knit_rd%"            "%knit_rd_all%"       
## [52] "%knit_watch%"         "%load_cache%"         "%myop%"              
## [55] "%normal_print%"       "%pandoc%"             "%pat_asciidoc%"      
## [58] "%pat_brew%"           "%pat_html%"           "%pat_md%"            
## [61] "%pat_rnw%"            "%pat_rst%"            "%pat_tex%"           
## [64] "%pat_textile%"        "%plot_crop%"          "%purl%"              
## [67] "%raw_output%"         "%rbind%"              "%read_chunk%"        
## [70] "%read_demo%"          "%read_rforge%"        "%render_asciidoc%"   
## [73] "%render_html%"        "%render_jekyll%"      "%render_latex%"      
## [76] "%render_listings%"    "%render_markdown%"    "%render_rst%"        
## [79] "%render_sweave%"      "%render_textile%"     "%restore_raw_output%"
## [82] "%rocco%"              "%rst2pdf%"            "%set_alias%"         
## [85] "%set_header%"         "%set_parent%"         "%spin%"              
## [88] "%spin_child%"         "%stitch%"             "%stitch_rhtml%"      
## [91] "%stitch_rmd%"         "%wrap_rmd%"           "%write_bib%"
`%purl%`
## function (..., documentation = 1L) 
## {
##     doc = opts_knit$get("documentation")
##     on.exit(opts_knit$set(documentation = doc))
##     opts_knit$set(documentation = documentation)
##     knit(..., tangle = TRUE)
## }
## <environment: namespace:knitr>

Advanced users can supply environments to the from and to arguments. This affords more control over where the functions come from and where the operators get assigned.

to_env = new.env()
from_env = new.env()
from_env$nextop = function(a, b, extra = 3){
  sqrt(a^2 + b^2) + extra
}
assign_operator = function(){
  grow(nextop, from = from_env, to = to_env)
}
assign_operator()
# 1 %nextop% 2 # throws an error since %nextop% is not defined in your workspace
eval(parse(text = "1 %nextop% 2"), envir = to_env)
## [1] 5.236068
bunch(from_env)
## character(0)
functions(from_env)
## [1] "nextop"
bunch(to_env)
## [1] "%nextop%"
functions(to_env)
## character(0)