## 17.6 Customising evaluation with functions

The above example used an environment that bound x and y to vectors. It’s less obvious that you also bind names to functions, allowing you to override the behaviour of existing functions. This is a big idea that we’ll come back to in Chapter 21 where I explore generating HTML and LaTeX from R. The example below gives you a taste of the power. Here I evaluate code in a special environment where * and + have been overridden to work with strings instead of numbers:

string_math <- function(x) {
e <- env(
caller_env(),
+ = function(x, y) paste0(x, y),
* = function(x, y) strrep(x, y)
)

eval(enexpr(x), e)
}

string_math("Hello " + name)
string_math(("x" * 2 + "-y") * 3)
#> [1] "xx-yxx-yxx-y"

dplyr takes this idea to the extreme, running code in an environment that generates SQL for execution in a remote database:

library(dplyr)
#>
#> Attaching package: 'dplyr'
#> The following objects are masked from 'package:stats':
#>
#>     filter, lag
#> The following objects are masked from 'package:base':
#>
#>     intersect, setdiff, setequal, union

con <- DBI::dbConnect(RSQLite::SQLite(), filename = ":memory:")
mtcars_db <- copy_to(con, mtcars)

mtcars_db %>%
filter(cyl > 2) %>%
select(mpg:hp) %>%
#> SELECT mpg, cyl, disp, hp
#> FROM mtcars
#> WHERE (cyl > 2.0)
DBI::dbDisconnect(con)