[med-svn] [r-cran-lazyeval] 07/12: New upstream version 0.2.1

Andreas Tille tille at debian.org
Fri Nov 10 09:20:44 UTC 2017


This is an automated email from the git hooks/post-receive script.

tille pushed a commit to branch master
in repository r-cran-lazyeval.

commit 98219b532aa440ec109fc894102135be653e4a51
Author: Andreas Tille <tille at debian.org>
Date:   Fri Nov 10 10:15:58 2017 +0100

    New upstream version 0.2.1
---
 DESCRIPTION                   |   8 +-
 MD5                           |  91 ++++++------
 NAMESPACE                     |  10 +-
 NEWS.md                       |  13 ++
 R/expr.R                      |   6 +-
 R/f-capture.R                 |   4 +-
 R/f-interp.R                  |   3 +-
 R/formula.R                   |  20 +--
 R/lazy-dots.R                 |   3 +-
 R/lazy.R                      |   3 +-
 R/lazyeval.R                  |   2 +
 README.md                     |   2 +-
 build/vignette.rds            | Bin 252 -> 253 bytes
 inst/doc/lazyeval-old.html    | 114 ++++++--------
 inst/doc/lazyeval.html        | 250 +++++++++++++++----------------
 man/all_dots.Rd               |   1 -
 man/as.lazy.Rd                |   1 -
 man/as_name.Rd                |   3 +-
 man/ast_.Rd                   |   3 +-
 man/auto_name.Rd              |   1 -
 man/call_modify.Rd            |   1 -
 man/call_new.Rd               |   1 -
 man/common_env.Rd             |   1 -
 man/expr_label.Rd             |   5 +-
 man/f_capture.Rd              |   3 +-
 man/f_eval.Rd                 |   6 +-
 man/f_interp.Rd               |   4 +-
 man/f_list.Rd                 |   3 +-
 man/f_new.Rd                  |   1 -
 man/f_rhs.Rd                  |   9 +-
 man/f_text.Rd                 |   3 +-
 man/f_unwrap.Rd               |   1 -
 man/function_new.Rd           |   1 -
 man/interp.Rd                 |   1 -
 man/is_formula.Rd             |   1 -
 man/is_lang.Rd                |   5 +-
 man/lazy_.Rd                  |   3 +-
 man/lazy_dots.Rd              |   1 -
 man/lazy_eval.Rd              |   1 -
 man/make_call.Rd              |   1 -
 man/missing_arg.Rd            |   1 -
 src/expr.c                    |   2 +-
 src/init.c                    |  30 ++++
 src/lazy.c                    |  10 +-
 src/name.c                    |  14 +-
 src/utils.c                   |  10 +-
 tests/testthat/test-formula.R |   4 +-
 vignettes/lazyeval.nb.html    | 335 ------------------------------------------
 48 files changed, 319 insertions(+), 677 deletions(-)

diff --git a/DESCRIPTION b/DESCRIPTION
index 201ab02..ad81e82 100644
--- a/DESCRIPTION
+++ b/DESCRIPTION
@@ -1,5 +1,5 @@
 Package: lazyeval
-Version: 0.2.0
+Version: 0.2.1
 Title: Lazy (Non-Standard) Evaluation
 Description: An alternative approach to non-standard evaluation using
     formulas. Provides a full implementation of LISP style 'quasiquotation',
@@ -13,11 +13,11 @@ LazyData: true
 Depends: R (>= 3.1.0)
 Suggests: knitr, rmarkdown (>= 0.2.65), testthat, covr
 VignetteBuilder: knitr
-RoxygenNote: 5.0.1
+RoxygenNote: 6.0.1
 NeedsCompilation: yes
-Packaged: 2016-06-10 21:38:52 UTC; hadley
+Packaged: 2017-10-18 22:37:44 UTC; lionel
 Author: Hadley Wickham [aut, cre],
   RStudio [cph]
 Maintainer: Hadley Wickham <hadley at rstudio.com>
 Repository: CRAN
-Date/Publication: 2016-06-12 19:03:08
+Date/Publication: 2017-10-29 22:59:36 UTC
diff --git a/MD5 b/MD5
index a20c62b..0264faa 100644
--- a/MD5
+++ b/MD5
@@ -1,63 +1,65 @@
-fa9cd2a9bbc39b62c157b6314731acd1 *DESCRIPTION
-7b2947f5d0d0271183df72fca2ce3e3d *NAMESPACE
-cf66555e902bf658a46f21098c4b3924 *NEWS.md
+b83aa4df133ff1780f623af003771305 *DESCRIPTION
+076be75efe0b6fdb85434c1d6ba4a81e *NAMESPACE
+9f6939434f914a3b7f539ce217df3326 *NEWS.md
 d9cc209f4c0c733a11ed93e673ae0d9c *R/ast.R
 befb1c81988ed1357c416f919528980d *R/call.R
 e3159cd804827c6d85885c17b284b5fb *R/complain.R
-77caaa0ea35cd37de5223d4e196a3ae8 *R/expr.R
-50c6c7b9a0ed29d6a0339267382cbc0b *R/f-capture.R
+b2388d07483695bad432af4278771633 *R/expr.R
+57e40b0dd45196bae1bd50f405a23129 *R/f-capture.R
 c1e8a4f2908cc985b4faed2c04bebc7f *R/f-eval.R
-937485929e7484b04ba928363c40783f *R/f-interp.R
-6af036082308c708e8c41c2feddfc342 *R/formula.R
+213fb437c2e4a967086694e3e2db8974 *R/f-interp.R
+1d0f8e3b2eaf491d129a04ebe3084280 *R/formula.R
 ea161e248423ef0d17885123c1065258 *R/function.R
 be4330310f7efddd7fefe5052db9a8e0 *R/language.R
 d9a423351a93e1514bfac54255d4eb28 *R/lazy-as.R
 f2b5984a77262840aea4bf29785ed9b9 *R/lazy-call.R
-657685967b8807536a446cb3b4e066e1 *R/lazy-dots.R
+b9ffe3bc4e4a0476f20941d79767c947 *R/lazy-dots.R
 66bfb57dbc11072d7581559830ba1994 *R/lazy-eval.R
 41ed7c6a852958828eb44d08374bff84 *R/lazy-interp.R
 3cbae872f5df31e044ddf79731550d93 *R/lazy-names.R
-1fb72726cd71726fd765f99b9201721d *R/lazy.R
+82c4b4197e5df808c9eca0b9b0bd9faa *R/lazy.R
+eaab07fb1d658479edaa8e1385a7ae05 *R/lazyeval.R
 4501ecd06bc9f3d7513cc558cc195440 *R/utils.R
-20befb8e739c2bb4a0f0b3127094c034 *README.md
-d81073433d99ffc4634fac4854ce8738 *build/vignette.rds
+0f459b4372bceb994acda6f5836a8cc7 *README.md
+add6e0109119aa6cf267084dd15b2c49 *build/vignette.rds
 01e2dd08598e3e44bab0fb7a03a40d6c *inst/doc/lazyeval-old.R
 fd0e6bc6fa61549d20cc69f641dd2ffd *inst/doc/lazyeval-old.Rmd
-eb784bcdb14416449e1f444429aad13d *inst/doc/lazyeval-old.html
+a908e650997ce0208a616ad5f7c69d35 *inst/doc/lazyeval-old.html
 5f895ae6e564ecd4855e5ae17b1e1216 *inst/doc/lazyeval.R
 036dd3ea1f555238004da3c88ffb2373 *inst/doc/lazyeval.Rmd
-10e7eaef568acaa72b0096c27dc303ce *inst/doc/lazyeval.html
-03e28452c0b2edfa94ed1082c8368ffd *man/all_dots.Rd
-c3709c4449a6bbda09c1517b1f5af844 *man/as.lazy.Rd
-9ab475b8e753f516261951deda3fa016 *man/as_name.Rd
-f0d6875f5040038fcf5c8c8a28f753ac *man/ast_.Rd
-fe5e4aaee2e4bf7e6c33e8f4c0325f47 *man/auto_name.Rd
-7065bdcd616febd822fd627fb5dfc80b *man/call_modify.Rd
-3adf4392696f87f3fe20be863e097030 *man/call_new.Rd
-cac4ff895c5a07de960880458d93e25c *man/common_env.Rd
-4c398d8819d35ab0ddfb33ec4362ccb5 *man/expr_label.Rd
-1adeb570aa4c952f60c2877a3e837765 *man/f_capture.Rd
-7de2d26c479c618917953141fe61b71a *man/f_eval.Rd
-52db51794b9bfd4bfd63e882a9580760 *man/f_interp.Rd
-86188063b7691e5ba7555efdc22b2ced *man/f_list.Rd
-ff05de5c1ca041f7c637b07e832e98ca *man/f_new.Rd
-d5bb30d0072508cc7df571477745646d *man/f_rhs.Rd
-fcfa4b57c381a89662600b1535f6bbf5 *man/f_text.Rd
-6006c0d80c0d8024f6079ee9ff6e387b *man/f_unwrap.Rd
-546aca85c89f0f07b635afab74dc6e93 *man/function_new.Rd
-6f3839e1f92d109ae2325a5377d04dca *man/interp.Rd
-0966ab35dae62a21e2725893d7db865c *man/is_formula.Rd
-20860876d74853d5434de1195ad5d1dd *man/is_lang.Rd
-47bdb7f92aa7939a613275d02cd33a5d *man/lazy_.Rd
-1699f8204d5ad958d59b44c089bb6605 *man/lazy_dots.Rd
-79e602e1583f70cd93abeb737506555f *man/lazy_eval.Rd
-911496ab1d254d0b1995552ad9b2bd12 *man/make_call.Rd
-d5dd6510243621a9e1db205e800c337c *man/missing_arg.Rd
-7b905d827832f25ae40fef01890066e9 *src/expr.c
+750bd2b0dab394af791c04c9169a68fa *inst/doc/lazyeval.html
+2c6ee8d0f2d6cf9583df82824633a7ec *man/all_dots.Rd
+2f412970013bfff969553cc5cdbf7414 *man/as.lazy.Rd
+4fa1680ecbd33e9f2accbed41fc3baa8 *man/as_name.Rd
+4901deef27855e3ef5092ac2e4057a75 *man/ast_.Rd
+1310232e76533965b20420bf90e30409 *man/auto_name.Rd
+1340d8a3bedefed84920b71fedc792b2 *man/call_modify.Rd
+42f82e62a13b78b7b320d47f22306e8b *man/call_new.Rd
+1a8c04aa15f32ebd4f1b7134e5e47177 *man/common_env.Rd
+f1a86b0424eda1d67dcfe1d087ed4ba0 *man/expr_label.Rd
+3a2dfc1787f0e86465012f83b49f37fd *man/f_capture.Rd
+723f0f8420caa731cc4728018ece4da2 *man/f_eval.Rd
+fdfbf4920db2dd295a7776ff8b96c8bb *man/f_interp.Rd
+fb3fd925c09ff6f29b25e47b8d0669b4 *man/f_list.Rd
+ab43799b3040137e6469cc910bfc641a *man/f_new.Rd
+f0a2c22aa74c49a34b1e3dc1932fe493 *man/f_rhs.Rd
+884e3f93ec645eaff34d3b9f741f8738 *man/f_text.Rd
+49fc315564f56e6c446f4473f18c0171 *man/f_unwrap.Rd
+0478841ebc4f4a9dd82b4e7e2f5f69fd *man/function_new.Rd
+a1aebb42db9afefd71c6d00bc831e54c *man/interp.Rd
+eb6f14cec04ba1c8edcc1a1248197b7e *man/is_formula.Rd
+4d2fea5d64ef556504c187239d3245df *man/is_lang.Rd
+5197c686f549745ac6a6978c4b2fe2b1 *man/lazy_.Rd
+0db962cf222cbe82f959174dd660805b *man/lazy_dots.Rd
+e4dd5b05f00327e486789b26be8f674a *man/lazy_eval.Rd
+4557247dd1c9ce7d6a78520aa770f55b *man/make_call.Rd
+4342c540bfd816fc182175e5b0608cd2 *man/missing_arg.Rd
+5a213920da3263a55dc830932737b7e0 *src/expr.c
+7aa5384ba84c293274b4add5c53118aa *src/init.c
 e4155ab688f6e7c66de0d688ece032ac *src/interp.c
-d7a002f57621390d47008a7a48f50034 *src/lazy.c
-c903c7364ad618995a6d13798a60695d *src/name.c
-ea674e2342add37360bafee9e0fbcbc2 *src/utils.c
+99f2d28770a76e1c6a6e1559ddfd1db4 *src/lazy.c
+5ff30a1fc26006eb8377347e329b1d13 *src/name.c
+83f89c0bd554828bf1472d59758a824f *src/utils.c
 26ca4f69c34debf19d0665cc61dcea80 *src/utils.h
 b43a93ea47dc4f6a64a4625fb67b87f6 *tests/testthat.R
 28ab6d5c95cce52309b007a83e869cd1 *tests/testthat/ast-irregular.txt
@@ -72,11 +74,10 @@ c31c22fe7c0f3ab3723dcf15b574e365 *tests/testthat/test-expr.R
 b5ea255aacfa712ab108dff7bc031543 *tests/testthat/test-f-interp.R
 f13ad194342bbc3166d97bae4d2c0f0a *tests/testthat/test-f-list.R
 11bfa6279aa0e9589ea9d4f1b6d62a6e *tests/testthat/test-f-unwrap.R
-ab37f7090d977e24438cd1ff79e371af *tests/testthat/test-formula.R
+81dc0f3c29e0df764289059a52026e02 *tests/testthat/test-formula.R
 cf2bc1d7126c6275bb6a66200c86cdc4 *tests/testthat/test-function.R
 4e12b82cde56263135ae960627dce9cf *tests/testthat/test-language.R
 7c37c5cf3fab082e9dfda9942e2f72e0 *tests/testthat/test-lazy.R
 dcd46b347706159f3b53165d13ee9272 *tests/testthat/test-names.R
 fd0e6bc6fa61549d20cc69f641dd2ffd *vignettes/lazyeval-old.Rmd
 036dd3ea1f555238004da3c88ffb2373 *vignettes/lazyeval.Rmd
-98671c6e82620ce1a9e731aeaa2bc674 *vignettes/lazyeval.nb.html
diff --git a/NAMESPACE b/NAMESPACE
index d1c9971..65b6721 100644
--- a/NAMESPACE
+++ b/NAMESPACE
@@ -93,12 +93,4 @@ export(missing_arg)
 export(uq)
 export(uqf)
 export(uqs)
-useDynLib(lazyeval,env)
-useDynLib(lazyeval,expr_env_)
-useDynLib(lazyeval,expr_find_)
-useDynLib(lazyeval,interp_)
-useDynLib(lazyeval,lhs)
-useDynLib(lazyeval,lhs_name)
-useDynLib(lazyeval,make_lazy)
-useDynLib(lazyeval,make_lazy_dots)
-useDynLib(lazyeval,rhs)
+useDynLib(lazyeval, .registration = TRUE)
diff --git a/NEWS.md b/NEWS.md
index 0553190..a34e3a5 100644
--- a/NEWS.md
+++ b/NEWS.md
@@ -1,3 +1,16 @@
+# lazyeval 0.2.1
+
+This is a maintenance release. The lazyeval package is no longer
+developed as the tidyverse is switching to tidy evaluation.
+
+* Use new registration system.
+
+* Switch from `SET_NAMED()` to `MARK_NOT_MUTABLE()` in prevision of an
+  API change in R core
+
+* No longer check the type of the sides of the formula.
+
+
 # lazyeval 0.2.0
 
 ## Formula-based lazy evaluation
diff --git a/R/expr.R b/R/expr.R
index 427ee7f..4a9ff18 100644
--- a/R/expr.R
+++ b/R/expr.R
@@ -69,20 +69,18 @@ expr_text_ <- function(x, width = 60L, nlines = Inf) {
   paste0(str, collapse = "\n")
 }
 
-#' @useDynLib lazyeval expr_find_
 #' @export
 #' @rdname expr_label
 expr_find <- function(x) {
-  .Call(expr_find_, quote(x), environment())
+  .Call(lazyeval_expr_find_, quote(x), environment())
 }
 
-#' @useDynLib lazyeval expr_env_
 #' @param default_env If supplied, \code{expr_env} will return this if the
 #'   promise has already been forced. Otherwise it will throw an error.
 #' @export
 #' @rdname expr_label
 expr_env <- function(x, default_env) {
-  env <- .Call(expr_env_, quote(x), environment())
+  env <- .Call(lazyeval_expr_env_, quote(x), environment())
 
   if (is.null(env)) {
     if (missing(default_env)) {
diff --git a/R/f-capture.R b/R/f-capture.R
index f278484..6ba0935 100644
--- a/R/f-capture.R
+++ b/R/f-capture.R
@@ -23,13 +23,13 @@
 #' h <- function(z) f_capture(z)
 #' f(a + b + c)
 f_capture <- function(x) {
-  lazy <- .Call(make_lazy, quote(x), environment(), TRUE)
+  lazy <- .Call(lazyeval_make_lazy, quote(x), environment(), TRUE)
   f_new(lazy$expr, env = lazy$env)
 }
 
 #' @export
 #' @rdname f_capture
 dots_capture <- function(..., .ignore_empty = TRUE) {
-  lazies <- .Call(make_lazy_dots, environment(), TRUE, .ignore_empty)
+  lazies <- .Call(lazyeval_make_lazy_dots, environment(), TRUE, .ignore_empty)
   lapply(lazies, function(x) f_new(x$expr, env = x$env))
 }
diff --git a/R/f-interp.R b/R/f-interp.R
index bc5c753..667a578 100644
--- a/R/f-interp.R
+++ b/R/f-interp.R
@@ -37,9 +37,8 @@
 #' f <- foo(10)
 #' f
 #' f_interp(f)
-#' @useDynLib lazyeval interp_
 f_interp <- function(f, data = NULL) {
-  f_rhs(f) <- .Call(interp_, f_rhs(f), f_env(f), data)
+  f_rhs(f) <- .Call(lazyeval_interp_, f_rhs(f), f_env(f), data)
   f
 }
 
diff --git a/R/formula.R b/R/formula.R
index 41445f2..73e23ec 100644
--- a/R/formula.R
+++ b/R/formula.R
@@ -8,12 +8,6 @@
 #' f_new(quote(a))
 #' f_new(quote(a), quote(b))
 f_new <- function(rhs, lhs = NULL, env = parent.frame()) {
-  if (!is_lang(rhs)) {
-    stop("`rhs` must be a language object", call. = FALSE)
-  }
-  if (!is_lang(lhs) && !is.null(lhs)) {
-    stop("`lhs` must be a language object", call. = FALSE)
-  }
   if (!is.environment(env)) {
     stop("`env` must be an environment", call. = FALSE)
   }
@@ -64,9 +58,8 @@ is_formula <- function(x) {
 #' f_lhs(x ~ y)
 #'
 #' f_env(~ x)
-#' @useDynLib lazyeval rhs
 f_rhs <- function(f) {
-  .Call(rhs, f)
+  .Call(lazyeval_rhs, f)
 }
 
 #' @export
@@ -78,9 +71,8 @@ f_rhs <- function(f) {
 
 #' @export
 #' @rdname f_rhs
-#' @useDynLib lazyeval lhs
 f_lhs <- function(f) {
-  .Call(lhs, f)
+  .Call(lazyeval_lhs, f)
 }
 
 #' @export
@@ -92,9 +84,8 @@ f_lhs <- function(f) {
 
 #' @export
 #' @rdname f_rhs
-#' @useDynLib lazyeval env
 f_env <- function(f) {
-  .Call(env, f)
+  .Call(lazyeval_env, f)
 }
 
 #' @export
@@ -168,16 +159,15 @@ f_unwrap <- function(f) {
 #' @param x An existing list
 #' @return A named list.
 #' @export
-#' @useDynLib lazyeval lhs_name
 #' @examples
 #' f_list("y" ~ x)
 #' f_list(a = "y" ~ a, ~ b, c = ~c)
 f_list <- function(...) {
-  .Call(lhs_name, list(...))
+  .Call(lazyeval_lhs_name, list(...))
 }
 
 #' @export
 #' @rdname f_list
 as_f_list <- function(x) {
-  .Call(lhs_name, x)
+  .Call(lazyeval_lhs_name, x)
 }
diff --git a/R/lazy-dots.R b/R/lazy-dots.R
index d18d1fd..84ec476 100644
--- a/R/lazy-dots.R
+++ b/R/lazy-dots.R
@@ -5,7 +5,6 @@
 #' @return A named list of \code{\link{lazy}} expressions.
 #' @inheritParams lazy
 #' @export
-#' @useDynLib lazyeval make_lazy_dots
 #' @examples
 #' lazy_dots(x = 1)
 #' lazy_dots(a, b, c * 4)
@@ -30,7 +29,7 @@
 #'
 #' c(lazy_dots(x = 1), lazy_dots(f))
 lazy_dots <- function(..., .follow_symbols = FALSE, .ignore_empty = FALSE) {
-  .Call(make_lazy_dots, environment(), .follow_symbols, .ignore_empty)
+  .Call(lazyeval_make_lazy_dots, environment(), .follow_symbols, .ignore_empty)
 }
 
 is.lazy_dots <- function(x) inherits(x, "lazy_dots")
diff --git a/R/lazy.R b/R/lazy.R
index 229ee53..5266bb9 100644
--- a/R/lazy.R
+++ b/R/lazy.R
@@ -48,9 +48,8 @@ lazy_ <- function(expr, env) {
 
 #' @rdname lazy_
 #' @export
-#' @useDynLib lazyeval make_lazy
 lazy <- function(expr, env = parent.frame(), .follow_symbols = TRUE) {
-  .Call(make_lazy, quote(expr), environment(), .follow_symbols)
+  .Call(lazyeval_make_lazy, quote(expr), environment(), .follow_symbols)
 }
 
 is.lazy <- function(x) inherits(x, "lazy")
diff --git a/R/lazyeval.R b/R/lazyeval.R
new file mode 100644
index 0000000..c663c20
--- /dev/null
+++ b/R/lazyeval.R
@@ -0,0 +1,2 @@
+#' @useDynLib lazyeval, .registration = TRUE
+NULL
diff --git a/README.md b/README.md
index f3c7237..9ee51b6 100644
--- a/README.md
+++ b/README.md
@@ -1,7 +1,7 @@
 # lazyeval
 
 [![Build Status](https://travis-ci.org/hadley/lazyeval.png?branch=master)](https://travis-ci.org/hadley/lazyeval)
-[![Coverage Status](https://img.shields.io/codecov/c/github/hadley/lazyeval/master.svg)](https://codecov.io/github/hadley/lazyeval?branch=master)
+[![Coverage Status](http://codecov.io/github/hadley/lazyeval/coverage.svg?branch=master)](http://codecov.io/github/hadley/lazyeval?branch=master)
 
 The lazyeval package provides tools that make it easier to correctly implement non-standard evaluation (NSE) in R. You use lazy evaluation by requiring the user to "quote" specially evaluated arguments with `~`, and then using the lazyeval package to compute with those formulas. It is also possible to eliminate the use of the `~` by converting promises to formulas. This does make programming with such functions a little harder, but it can be worth it in certain situations. See `vignette( [...]
 
diff --git a/build/vignette.rds b/build/vignette.rds
index fe95161..797eb12 100644
Binary files a/build/vignette.rds and b/build/vignette.rds differ
diff --git a/inst/doc/lazyeval-old.html b/inst/doc/lazyeval-old.html
index 6a6b2fb..33f7740 100644
--- a/inst/doc/lazyeval-old.html
+++ b/inst/doc/lazyeval-old.html
@@ -4,14 +4,14 @@
 
 <head>
 
-<meta charset="utf-8">
+<meta charset="utf-8" />
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <meta name="generator" content="pandoc" />
 
 <meta name="viewport" content="width=device-width, initial-scale=1">
 
 
-<meta name="date" content="2016-06-10" />
+<meta name="date" content="2017-10-19" />
 
 <title>Lazyeval: a new approach to NSE</title>
 
@@ -19,46 +19,28 @@
 
 <style type="text/css">code{white-space: pre;}</style>
 <style type="text/css">
-div.sourceCode { overflow-x: auto; }
 table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
   margin: 0; padding: 0; vertical-align: baseline; border: none; }
 table.sourceCode { width: 100%; line-height: 100%; }
 td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
 td.sourceCode { padding-left: 5px; }
-code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
-code > span.dt { color: #902000; } /* DataType */
-code > span.dv { color: #40a070; } /* DecVal */
-code > span.bn { color: #40a070; } /* BaseN */
-code > span.fl { color: #40a070; } /* Float */
-code > span.ch { color: #4070a0; } /* Char */
-code > span.st { color: #4070a0; } /* String */
-code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
-code > span.ot { color: #007020; } /* Other */
-code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
-code > span.fu { color: #06287e; } /* Function */
-code > span.er { color: #ff0000; font-weight: bold; } /* Error */
-code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
-code > span.cn { color: #880000; } /* Constant */
-code > span.sc { color: #4070a0; } /* SpecialChar */
-code > span.vs { color: #4070a0; } /* VerbatimString */
-code > span.ss { color: #bb6688; } /* SpecialString */
-code > span.im { } /* Import */
-code > span.va { color: #19177c; } /* Variable */
-code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
-code > span.op { color: #666666; } /* Operator */
-code > span.bu { } /* BuiltIn */
-code > span.ex { } /* Extension */
-code > span.pp { color: #bc7a00; } /* Preprocessor */
-code > span.at { color: #7d9029; } /* Attribute */
-code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
-code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
-code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
-code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+code > span.kw { color: #007020; font-weight: bold; }
+code > span.dt { color: #902000; }
+code > span.dv { color: #40a070; }
+code > span.bn { color: #40a070; }
+code > span.fl { color: #40a070; }
+code > span.ch { color: #4070a0; }
+code > span.st { color: #4070a0; }
+code > span.co { color: #60a0b0; font-style: italic; }
+code > span.ot { color: #007020; }
+code > span.al { color: #ff0000; font-weight: bold; }
+code > span.fu { color: #06287e; }
+code > span.er { color: #ff0000; font-weight: bold; }
 </style>
 
 
 
-<link href="data:text/css;charset=utf-8,body%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0Amargin%3A%201em%20auto%3B%0Amax%2Dwidth%3A%20700px%3B%0Aoverflow%3A%20visible%3B%0Apadding%2Dleft%3A%202em%3B%0Apadding%2Dright%3A%202em%3B%0Afont%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E35%3B%0A%7D%0A%23header%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%23TOC%20%7B%0Aclear%3A%20bot [...]
+<link href="data:text/css,body%20%7B%0A%20%20background%2Dcolor%3A%20%23fff%3B%0A%20%20margin%3A%201em%20auto%3B%0A%20%20max%2Dwidth%3A%20700px%3B%0A%20%20overflow%3A%20visible%3B%0A%20%20padding%2Dleft%3A%202em%3B%0A%20%20padding%2Dright%3A%202em%3B%0A%20%20font%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0A%20%20font%2Dsize%3A%2014px%3B%0A%20%20line%2Dheight%3A%201%2E35%3B%0A%7D%0A%0A%23header%20%7B%0A%20%20text%2Dalign%3A% [...]
 
 </head>
 
@@ -68,7 +50,7 @@ code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Inf
 
 
 <h1 class="title toc-ignore">Lazyeval: a new approach to NSE</h1>
-<h4 class="date"><em>2016-06-10</em></h4>
+<h4 class="date"><em>2017-10-19</em></h4>
 
 
 
@@ -82,41 +64,41 @@ code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Inf
 <div id="lazy" class="section level2">
 <h2><code>lazy()</code></h2>
 <p>The key tool that makes this approach possible is <code>lazy()</code>, an equivalent to <code>substitute()</code> that captures both expression and environment associated with a function argument:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">library</span>(lazyeval)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">library</span>(lazyeval)
 f <-<span class="st"> </span>function(<span class="dt">x =</span> a -<span class="st"> </span>b) {
   <span class="kw">lazy</span>(x)
 }
 <span class="kw">f</span>()
 <span class="co">#> <lazy></span>
 <span class="co">#>   expr: a - b</span>
-<span class="co">#>   env:  <environment: 0x7fd4dbb11ff0></span>
+<span class="co">#>   env:  <environment: 0x7fe58944e208></span>
 <span class="kw">f</span>(a +<span class="st"> </span>b)
 <span class="co">#> <lazy></span>
 <span class="co">#>   expr: a + b</span>
-<span class="co">#>   env:  <environment: R_GlobalEnv></span></code></pre></div>
+<span class="co">#>   env:  <environment: R_GlobalEnv></span></code></pre>
 <p>As a complement to <code>eval()</code>, the lazy package provides <code>lazy_eval()</code> that uses the environment associated with the lazy object:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">a <-<span class="st"> </span><span class="dv">10</span>
+<pre class="sourceCode r"><code class="sourceCode r">a <-<span class="st"> </span><span class="dv">10</span>
 b <-<span class="st"> </span><span class="dv">1</span>
 <span class="kw">lazy_eval</span>(<span class="kw">f</span>())
 <span class="co">#> [1] 9</span>
 <span class="kw">lazy_eval</span>(<span class="kw">f</span>(a +<span class="st"> </span>b))
-<span class="co">#> [1] 11</span></code></pre></div>
+<span class="co">#> [1] 11</span></code></pre>
 <p>The second argument to lazy eval is a list or data frame where names should be looked up first:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">lazy_eval</span>(<span class="kw">f</span>(), <span class="kw">list</span>(<span class="dt">a =</span> <span class="dv">1</span>))
-<span class="co">#> [1] 0</span></code></pre></div>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">lazy_eval</span>(<span class="kw">f</span>(), <span class="kw">list</span>(<span class="dt">a =</span> <span class="dv">1</span>))
+<span class="co">#> [1] 0</span></code></pre>
 <p><code>lazy_eval()</code> also works with formulas, since they contain the same information as a lazy object: an expression (only the RHS is used by convention) and an environment:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">lazy_eval</span>(~<span class="st"> </span>a +<span class="st"> </span>b)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">lazy_eval</span>(~<span class="st"> </span>a +<span class="st"> </span>b)
 <span class="co">#> [1] 11</span>
 h <-<span class="st"> </span>function(i) {
   ~<span class="st"> </span><span class="dv">10</span> +<span class="st"> </span>i
 }
 <span class="kw">lazy_eval</span>(<span class="kw">h</span>(<span class="dv">1</span>))
-<span class="co">#> [1] 11</span></code></pre></div>
+<span class="co">#> [1] 11</span></code></pre>
 </div>
 <div id="standard-evaluation" class="section level2">
 <h2>Standard evaluation</h2>
 <p>Whenever we need a function that does non-standard evaluation, always write the standard evaluation version first. For example, let’s implement our own version of <code>subset()</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">subset2_ <-<span class="st"> </span>function(df, condition) {
+<pre class="sourceCode r"><code class="sourceCode r">subset2_ <-<span class="st"> </span>function(df, condition) {
   r <-<span class="st"> </span><span class="kw">lazy_eval</span>(condition, df)
   r <-<span class="st"> </span>r &<span class="st"> </span>!<span class="kw">is.na</span>(r)
   df[r, , drop =<span class="st"> </span><span class="ot">FALSE</span>]
@@ -125,9 +107,9 @@ h <-<span class="st"> </span>function(i) {
 <span class="kw">subset2_</span>(mtcars, <span class="kw">lazy</span>(mpg ><span class="st"> </span><span class="dv">31</span>))
 <span class="co">#>     mpg cyl disp hp drat    wt  qsec vs am gear carb</span>
 <span class="co">#> 18 32.4   4 78.7 66 4.08 2.200 19.47  1  1    4    1</span>
-<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre></div>
+<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre>
 <p><code>lazy_eval()</code> will always coerce it’s first argument into a lazy object, so a variety of specifications will work:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">subset2_</span>(mtcars, ~mpg ><span class="st"> </span><span class="dv">31</span>)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">subset2_</span>(mtcars, ~mpg ><span class="st"> </span><span class="dv">31</span>)
 <span class="co">#>     mpg cyl disp hp drat    wt  qsec vs am gear carb</span>
 <span class="co">#> 18 32.4   4 78.7 66 4.08 2.200 19.47  1  1    4    1</span>
 <span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span>
@@ -138,34 +120,34 @@ h <-<span class="st"> </span>function(i) {
 <span class="kw">subset2_</span>(mtcars, <span class="st">"mpg > 31"</span>)
 <span class="co">#>     mpg cyl disp hp drat    wt  qsec vs am gear carb</span>
 <span class="co">#> 18 32.4   4 78.7 66 4.08 2.200 19.47  1  1    4    1</span>
-<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre></div>
+<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre>
 <p>Note that quoted called and strings don’t have environments associated with them, so <code>as.lazy()</code> defaults to using <code>baseenv()</code>. This will work if the expression is self-contained (i.e. doesn’t contain any references to variables in the local environment), and will otherwise fail quickly and robustly.</p>
 </div>
 <div id="non-standard-evaluation" class="section level2">
 <h2>Non-standard evaluation</h2>
 <p>With the SE version in hand, writing the NSE version is easy. We just use <code>lazy()</code> to capture the unevaluated expression and corresponding environment:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">subset2 <-<span class="st"> </span>function(df, condition) {
+<pre class="sourceCode r"><code class="sourceCode r">subset2 <-<span class="st"> </span>function(df, condition) {
   <span class="kw">subset2_</span>(df, <span class="kw">lazy</span>(condition))
 }
 <span class="kw">subset2</span>(mtcars, mpg ><span class="st"> </span><span class="dv">31</span>)
 <span class="co">#>     mpg cyl disp hp drat    wt  qsec vs am gear carb</span>
 <span class="co">#> 18 32.4   4 78.7 66 4.08 2.200 19.47  1  1    4    1</span>
-<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre></div>
+<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre>
 <p>This standard evaluation escape hatch is very important because it allows us to implement different NSE approaches. For example, we could create a subsetting function that finds all rows where a variable is above a threshold:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">above_threshold <-<span class="st"> </span>function(df, var, threshold) {
+<pre class="sourceCode r"><code class="sourceCode r">above_threshold <-<span class="st"> </span>function(df, var, threshold) {
   cond <-<span class="st"> </span><span class="kw">interp</span>(~<span class="st"> </span>var ><span class="st"> </span>x, <span class="dt">var =</span> <span class="kw">lazy</span>(var), <span class="dt">x =</span> threshold)
   <span class="kw">subset2_</span>(df, cond)
 }
 <span class="kw">above_threshold</span>(mtcars, mpg, <span class="dv">31</span>)
 <span class="co">#>     mpg cyl disp hp drat    wt  qsec vs am gear carb</span>
 <span class="co">#> 18 32.4   4 78.7 66 4.08 2.200 19.47  1  1    4    1</span>
-<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre></div>
+<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre>
 <p>Here we’re using <code>interp()</code> to modify a formula. We use the value of <code>threshold</code> and the expression in by <code>var</code>.</p>
 </div>
 <div id="scoping" class="section level2">
 <h2>Scoping</h2>
 <p>Because <code>lazy()</code> captures the environment associated with the function argument, we automatically avoid a subtle scoping bug present in <code>subset()</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">31</span>
+<pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">31</span>
 f1 <-<span class="st"> </span>function(...) {
   x <-<span class="st"> </span><span class="dv">30</span>
   <span class="kw">subset</span>(mtcars, ...)
@@ -186,36 +168,36 @@ f2 <-<span class="st"> </span>function(...) {
 <span class="kw">f2</span>(mpg ><span class="st"> </span>x)
 <span class="co">#>     mpg cyl disp hp drat    wt  qsec vs am gear carb</span>
 <span class="co">#> 18 32.4   4 78.7 66 4.08 2.200 19.47  1  1    4    1</span>
-<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre></div>
+<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre>
 <p><code>lazy()</code> has another advantage over <code>substitute()</code> - by default, it follows promises across function invocations. This simplifies the casual use of NSE.</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">31</span>
+<pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">31</span>
 g1 <-<span class="st"> </span>function(comp) {
   x <-<span class="st"> </span><span class="dv">30</span>
   <span class="kw">subset</span>(mtcars, comp)
 }
 <span class="kw">g1</span>(mpg ><span class="st"> </span>x)
-<span class="co">#> Error: object 'mpg' not found</span></code></pre></div>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">g2 <-<span class="st"> </span>function(comp) {
+<span class="co">#> Error: object 'mpg' not found</span></code></pre>
+<pre class="sourceCode r"><code class="sourceCode r">g2 <-<span class="st"> </span>function(comp) {
   x <-<span class="st"> </span><span class="dv">30</span>
   <span class="kw">subset2</span>(mtcars, comp)
 }
 <span class="kw">g2</span>(mpg ><span class="st"> </span>x)
 <span class="co">#>     mpg cyl disp hp drat    wt  qsec vs am gear carb</span>
 <span class="co">#> 18 32.4   4 78.7 66 4.08 2.200 19.47  1  1    4    1</span>
-<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre></div>
+<span class="co">#> 20 33.9   4 71.1 65 4.22 1.835 19.90  1  1    4    1</span></code></pre>
 <p>Note that <code>g2()</code> doesn’t have a standard-evaluation escape hatch, so it’s not suitable for programming with in the same way that <code>subset2_()</code> is.</p>
 </div>
 <div id="chained-promises" class="section level2">
 <h2>Chained promises</h2>
 <p>Take the following example:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">library</span>(lazyeval)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">library</span>(lazyeval)
 f1 <-<span class="st"> </span>function(x) <span class="kw">lazy</span>(x)
 g1 <-<span class="st"> </span>function(y) <span class="kw">f1</span>(y)
 
 <span class="kw">g1</span>(a +<span class="st"> </span>b)
 <span class="co">#> <lazy></span>
 <span class="co">#>   expr: a + b</span>
-<span class="co">#>   env:  <environment: R_GlobalEnv></span></code></pre></div>
+<span class="co">#>   env:  <environment: R_GlobalEnv></span></code></pre>
 <p><code>lazy()</code> returns <code>a + b</code> because it always tries to find the top-level promise.</p>
 <p>In this case the process looks like this:</p>
 <ol style="list-style-type: decimal">
@@ -226,23 +208,23 @@ g1 <-<span class="st"> </span>function(y) <span class="kw">f1</span>(y)
 <li>The expression is not a symbol, so stop.</li>
 </ol>
 <p>Occasionally, you want to avoid this recursive behaviour, so you can use <code>follow_symbol = FALSE</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">f2 <-<span class="st"> </span>function(x) <span class="kw">lazy</span>(x, <span class="dt">.follow_symbols =</span> <span class="ot">FALSE</span>)
+<pre class="sourceCode r"><code class="sourceCode r">f2 <-<span class="st"> </span>function(x) <span class="kw">lazy</span>(x, <span class="dt">.follow_symbols =</span> <span class="ot">FALSE</span>)
 g2 <-<span class="st"> </span>function(y) <span class="kw">f2</span>(y)
 
 <span class="kw">g2</span>(a +<span class="st"> </span>b)
 <span class="co">#> <lazy></span>
 <span class="co">#>   expr: x</span>
-<span class="co">#>   env:  <environment: 0x7fd4dc8465b8></span></code></pre></div>
+<span class="co">#>   env:  <environment: 0x7fe589034c00></span></code></pre>
 <p>Either way, if you evaluate the lazy expression you’ll get the same result:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">a <-<span class="st"> </span><span class="dv">10</span>
+<pre class="sourceCode r"><code class="sourceCode r">a <-<span class="st"> </span><span class="dv">10</span>
 b <-<span class="st"> </span><span class="dv">1</span>
 
 <span class="kw">lazy_eval</span>(<span class="kw">g1</span>(a +<span class="st"> </span>b))
 <span class="co">#> [1] 11</span>
 <span class="kw">lazy_eval</span>(<span class="kw">g2</span>(a +<span class="st"> </span>b))
-<span class="co">#> [1] 11</span></code></pre></div>
+<span class="co">#> [1] 11</span></code></pre>
 <p>Note that the resolution of chained promises only works with unevaluated objects. This is because R deletes the information about the environment associated with a promise when it has been forced, so that the garbage collector is allowed to remove the environment from memory in case it is no longer used. <code>lazy()</code> will fail with an error in such situations.</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">var <-<span class="st"> </span><span class="dv">0</span>
+<pre class="sourceCode r"><code class="sourceCode r">var <-<span class="st"> </span><span class="dv">0</span>
 
 f3 <-<span class="st"> </span>function(x) {
   <span class="kw">force</span>(x)
@@ -250,7 +232,7 @@ f3 <-<span class="st"> </span>function(x) {
 }
 
 <span class="kw">f3</span>(var)
-<span class="co">#> Error in lazy(x): Promise has already been forced</span></code></pre></div>
+<span class="co">#> Error in lazy(x): Promise has already been forced</span></code></pre>
 </div>
 
 
@@ -260,7 +242,7 @@ f3 <-<span class="st"> </span>function(x) {
   (function () {
     var script = document.createElement("script");
     script.type = "text/javascript";
-    script.src  = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+    script.src  = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
     document.getElementsByTagName("head")[0].appendChild(script);
   })();
 </script>
diff --git a/inst/doc/lazyeval.html b/inst/doc/lazyeval.html
index 55134da..5be38cc 100644
--- a/inst/doc/lazyeval.html
+++ b/inst/doc/lazyeval.html
@@ -4,7 +4,7 @@
 
 <head>
 
-<meta charset="utf-8">
+<meta charset="utf-8" />
 <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
 <meta name="generator" content="pandoc" />
 
@@ -12,7 +12,7 @@
 
 <meta name="author" content="Hadley Wickham" />
 
-<meta name="date" content="2016-06-10" />
+<meta name="date" content="2017-10-19" />
 
 <title>Non-standard evaluation</title>
 
@@ -20,46 +20,28 @@
 
 <style type="text/css">code{white-space: pre;}</style>
 <style type="text/css">
-div.sourceCode { overflow-x: auto; }
 table.sourceCode, tr.sourceCode, td.lineNumbers, td.sourceCode {
   margin: 0; padding: 0; vertical-align: baseline; border: none; }
 table.sourceCode { width: 100%; line-height: 100%; }
 td.lineNumbers { text-align: right; padding-right: 4px; padding-left: 4px; color: #aaaaaa; border-right: 1px solid #aaaaaa; }
 td.sourceCode { padding-left: 5px; }
-code > span.kw { color: #007020; font-weight: bold; } /* Keyword */
-code > span.dt { color: #902000; } /* DataType */
-code > span.dv { color: #40a070; } /* DecVal */
-code > span.bn { color: #40a070; } /* BaseN */
-code > span.fl { color: #40a070; } /* Float */
-code > span.ch { color: #4070a0; } /* Char */
-code > span.st { color: #4070a0; } /* String */
-code > span.co { color: #60a0b0; font-style: italic; } /* Comment */
-code > span.ot { color: #007020; } /* Other */
-code > span.al { color: #ff0000; font-weight: bold; } /* Alert */
-code > span.fu { color: #06287e; } /* Function */
-code > span.er { color: #ff0000; font-weight: bold; } /* Error */
-code > span.wa { color: #60a0b0; font-weight: bold; font-style: italic; } /* Warning */
-code > span.cn { color: #880000; } /* Constant */
-code > span.sc { color: #4070a0; } /* SpecialChar */
-code > span.vs { color: #4070a0; } /* VerbatimString */
-code > span.ss { color: #bb6688; } /* SpecialString */
-code > span.im { } /* Import */
-code > span.va { color: #19177c; } /* Variable */
-code > span.cf { color: #007020; font-weight: bold; } /* ControlFlow */
-code > span.op { color: #666666; } /* Operator */
-code > span.bu { } /* BuiltIn */
-code > span.ex { } /* Extension */
-code > span.pp { color: #bc7a00; } /* Preprocessor */
-code > span.at { color: #7d9029; } /* Attribute */
-code > span.do { color: #ba2121; font-style: italic; } /* Documentation */
-code > span.an { color: #60a0b0; font-weight: bold; font-style: italic; } /* Annotation */
-code > span.cv { color: #60a0b0; font-weight: bold; font-style: italic; } /* CommentVar */
-code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Information */
+code > span.kw { color: #007020; font-weight: bold; }
+code > span.dt { color: #902000; }
+code > span.dv { color: #40a070; }
+code > span.bn { color: #40a070; }
+code > span.fl { color: #40a070; }
+code > span.ch { color: #4070a0; }
+code > span.st { color: #4070a0; }
+code > span.co { color: #60a0b0; font-style: italic; }
+code > span.ot { color: #007020; }
+code > span.al { color: #ff0000; font-weight: bold; }
+code > span.fu { color: #06287e; }
+code > span.er { color: #ff0000; font-weight: bold; }
 </style>
 
 
 
-<link href="data:text/css;charset=utf-8,body%20%7B%0Abackground%2Dcolor%3A%20%23fff%3B%0Amargin%3A%201em%20auto%3B%0Amax%2Dwidth%3A%20700px%3B%0Aoverflow%3A%20visible%3B%0Apadding%2Dleft%3A%202em%3B%0Apadding%2Dright%3A%202em%3B%0Afont%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0Afont%2Dsize%3A%2014px%3B%0Aline%2Dheight%3A%201%2E35%3B%0A%7D%0A%23header%20%7B%0Atext%2Dalign%3A%20center%3B%0A%7D%0A%23TOC%20%7B%0Aclear%3A%20bot [...]
+<link href="data:text/css,body%20%7B%0A%20%20background%2Dcolor%3A%20%23fff%3B%0A%20%20margin%3A%201em%20auto%3B%0A%20%20max%2Dwidth%3A%20700px%3B%0A%20%20overflow%3A%20visible%3B%0A%20%20padding%2Dleft%3A%202em%3B%0A%20%20padding%2Dright%3A%202em%3B%0A%20%20font%2Dfamily%3A%20%22Open%20Sans%22%2C%20%22Helvetica%20Neue%22%2C%20Helvetica%2C%20Arial%2C%20sans%2Dserif%3B%0A%20%20font%2Dsize%3A%2014px%3B%0A%20%20line%2Dheight%3A%201%2E35%3B%0A%7D%0A%0A%23header%20%7B%0A%20%20text%2Dalign%3A% [...]
 
 </head>
 
@@ -70,19 +52,19 @@ code > span.in { color: #60a0b0; font-weight: bold; font-style: italic; } /* Inf
 
 <h1 class="title toc-ignore">Non-standard evaluation</h1>
 <h4 class="author"><em>Hadley Wickham</em></h4>
-<h4 class="date"><em>2016-06-10</em></h4>
+<h4 class="date"><em>2017-10-19</em></h4>
 
 
 
 <p>This document describes lazyeval, a package that provides principled tools to perform non-standard evaluation (NSE) in R. You should read this vignette if you want to program with packages like dplyr and ggplot2<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a>, or you want a principled way of working with delayed expressions in your own package. As the name suggests, non-standard evaluation breaks away from the standard evaluation (SE) rules in order to do something spec [...]
 <ol style="list-style-type: decimal">
 <li><p><strong>Labelling</strong> enhances plots and tables by using the expressions supplied to a function, rather than their values. For example, note the axis labels in this plot:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">par</span>(<span class="dt">mar =</span> <span class="kw">c</span>(<span class="fl">4.5</span>, <span class="fl">4.5</span>, <span class="dv">1</span>, <span class="fl">0.5</span>))
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">par</span>(<span class="dt">mar =</span> <span class="kw">c</span>(<span class="fl">4.5</span>, <span class="fl">4.5</span>, <span class="dv">1</span>, <span class="fl">0.5</span>))
 grid <-<span class="st"> </span><span class="kw">seq</span>(<span class="dv">0</span>, <span class="dv">2</span> *<span class="st"> </span>pi, <span class="dt">length =</span> <span class="dv">100</span>)
-<span class="kw">plot</span>(grid, <span class="kw">sin</span>(grid), <span class="dt">type =</span> <span class="st">"l"</span>)</code></pre></div>
+<span class="kw">plot</span>(grid, <span class="kw">sin</span>(grid), <span class="dt">type =</span> <span class="st">"l"</span>)</code></pre>
 <p><img src="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAYAAAADwCAYAAAAJkrPKAAAEDWlDQ1BJQ0MgUHJvZmlsZQAAOI2NVV1oHFUUPrtzZyMkzlNsNIV0qD8NJQ2TVjShtLp/3d02bpZJNtoi6GT27s6Yyc44M7v9oU9FUHwx6psUxL+3gCAo9Q/bPrQvlQol2tQgKD60+INQ6Ium65k7M5lpurHeZe58853vnnvuuWfvBei5qliWkRQBFpquLRcy4nOHj4g9K5CEh6AXBqFXUR0rXalMAjZPC3e1W99Dwntf2dXd/p+tt0YdFSBxH2Kz5qgLiI8B8KdVy3YBevqRHz/qWh72Yui3MUDEL3q44WPXw3M+fo1pZuQs4tOIBVVTaoiXEI/MxfhGDPsxsNZfoE1q66ro5aJim3XdoLFw72H+n23BaIXzbcOnz5mfPoTvYVz7KzUl5+FRxEuqkp9G/Ajia [...]
 <li><p><strong>Non-standard scoping</strong> looks for objects in places other than the current environment. For example, base R has <code>with()</code>, <code>subset()</code>, and <code>transform()</code> that look for objects in a data frame (or list) before the current environment:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">df <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="kw">c</span>(<span class="dv">1</span>, <span class="dv">5</span>, <span class="dv">4</span>, <span class="dv">2</span>, <span class="dv">3</span>), <span class="dt">y =</span> <span class="kw">c</span>(<span class="dv">2</span>, <span class="dv">1</span>, <span class="dv">5</span>, <span class="dv">4</sp [...]
+<pre class="sourceCode r"><code class="sourceCode r">df <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="kw">c</span>(<span class="dv">1</span>, <span class="dv">5</span>, <span class="dv">4</span>, <span class="dv">2</span>, <span class="dv">3</span>), <span class="dt">y =</span> <span class="kw">c</span>(<span class="dv">2</span>, <span class="dv">1</span>, <span class="dv">5</span>, <span class="dv">4</span>, <span class="dv">3< [...]
 
 <span class="kw">with</span>(df, <span class="kw">mean</span>(x))
 <span class="co">#> [1] 3</span>
@@ -95,32 +77,32 @@ grid <-<span class="st"> </span><span class="kw">seq</span>(<span class="dv">
 <span class="co">#> 2 5 1 6</span>
 <span class="co">#> 3 4 5 9</span>
 <span class="co">#> 4 2 4 6</span>
-<span class="co">#> 5 3 3 6</span></code></pre></div></li>
+<span class="co">#> 5 3 3 6</span></code></pre></li>
 <li><p><strong>Metaprogramming</strong> is a catch-all term that covers all other uses of NSE (such as in <code>bquote()</code> and <code>library()</code>). Metaprogramming is so called because it involves computing on the unevaluated code in some way.</p></li>
 </ol>
-<p>This document is broadly organised according to the three types of non-standard evaluation described above. The main difference is that after <a href="#labelling">labelling</a>, we’ll take a detour to learn more about <a href="#formulas">formulas</a>. You’re probably familiar with formulas from linear models (e.g. <code>lm(mpg ~ displ, data = mtcars)</code>) but formulas are more than just a tool for modelling: they are a general way of capturing an unevaluated expression.</p>
+<p>This document is broadly organised according to the three types of non-standard evaluation described above. The main difference is that after [labelling], we’ll take a detour to learn more about [formulas]. You’re probably familiar with formulas from linear models (e.g. <code>lm(mpg ~ displ, data = mtcars)</code>) but formulas are more than just a tool for modelling: they are a general way of capturing an unevaluated expression.</p>
 <p>The approaches recommended here are quite different to my previous generation of recommendations. I am fairly confident these new approaches are correct, and will not have to change substantially again. The current tools make it easy to solve a number of practical problems that were previously challenging and are rooted in <a href="http://repository.readscheme.org/ftp/papers/pepm99/bawden.pdf">long-standing theory</a>.</p>
 <div id="labelling" class="section level2">
 <h2>Labelling</h2>
 <p>In base R, the classic way to turn an argument into a label is to use <code>deparse(substitute(x))</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">my_label <-<span class="st"> </span>function(x) <span class="kw">deparse</span>(<span class="kw">substitute</span>(x))
+<pre class="sourceCode r"><code class="sourceCode r">my_label <-<span class="st"> </span>function(x) <span class="kw">deparse</span>(<span class="kw">substitute</span>(x))
 <span class="kw">my_label</span>(x +<span class="st"> </span>y)
-<span class="co">#> [1] "x + y"</span></code></pre></div>
+<span class="co">#> [1] "x + y"</span></code></pre>
 <p>There are two potential problems with this approach:</p>
 <ol style="list-style-type: decimal">
 <li><p>For long some expressions, <code>deparse()</code> generates a character vector with length > 1:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">my_label</span>({
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">my_label</span>({
   a +<span class="st"> </span>b
   c +<span class="st"> </span>d
 })
-<span class="co">#> [1] "{"         "    a + b" "    c + d" "}"</span></code></pre></div></li>
+<span class="co">#> [1] "{"         "    a + b" "    c + d" "}"</span></code></pre></li>
 <li><p><code>substitute()</code> only looks one level up, so you lose the original label if the function isn’t called directly:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">my_label2 <-<span class="st"> </span>function(x) <span class="kw">my_label</span>(x)
+<pre class="sourceCode r"><code class="sourceCode r">my_label2 <-<span class="st"> </span>function(x) <span class="kw">my_label</span>(x)
 <span class="kw">my_label2</span>(a +<span class="st"> </span>b)
-<span class="co">#> [1] "x"</span></code></pre></div></li>
+<span class="co">#> [1] "x"</span></code></pre></li>
 </ol>
 <p>Both of these problems are resolved by <code>lazyeval::expr_text()</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">my_label <-<span class="st"> </span>function(x) <span class="kw">expr_text</span>(x)
+<pre class="sourceCode r"><code class="sourceCode r">my_label <-<span class="st"> </span>function(x) <span class="kw">expr_text</span>(x)
 my_label2 <-<span class="st"> </span>function(x) <span class="kw">my_label</span>(x)
    
 <span class="kw">my_label</span>({
@@ -129,32 +111,32 @@ my_label2 <-<span class="st"> </span>function(x) <span class="kw">my_label</s
 })
 <span class="co">#> [1] "{\n    a + b\n    c + d\n}"</span>
 <span class="kw">my_label2</span>(a +<span class="st"> </span>b)
-<span class="co">#> [1] "a + b"</span></code></pre></div>
+<span class="co">#> [1] "a + b"</span></code></pre>
 <p>There are two variations on the theme of <code>expr_text()</code>:</p>
 <ul>
-<li><p><code>expr_find()</code> find the underlying expression. It works similarly to <code>substitute()</code> but will follow a chain of promises back up to the original expression. This is often useful for <a href="#metaprogramming">metaprogramming</a>.</p></li>
+<li><p><code>expr_find()</code> find the underlying expression. It works similarly to <code>substitute()</code> but will follow a chain of promises back up to the original expression. This is often useful for [metaprogramming].</p></li>
 <li><p><code>expr_label()</code> is a customised version of <code>expr_text()</code> that produces labels designed to be used in messages to the user:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">expr_label</span>(x)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">expr_label</span>(x)
 <span class="co">#> [1] "`x`"</span>
 <span class="kw">expr_label</span>(a +<span class="st"> </span>b +<span class="st"> </span>c)
 <span class="co">#> [1] "`a + b + c`"</span>
 <span class="kw">expr_label</span>(<span class="kw">foo</span>({
   x +<span class="st"> </span>y
 }))
-<span class="co">#> [1] "`foo(...)`"</span></code></pre></div></li>
+<span class="co">#> [1] "`foo(...)`"</span></code></pre></li>
 </ul>
 <div id="exercises" class="section level3">
 <h3>Exercises</h3>
 <ol style="list-style-type: decimal">
 <li><p><code>plot()</code> uses <code>deparse(substitute(x))</code> to generate labels for the x and y axes. Can you generate input that causes it to display bad labels? Write your own wrapper around <code>plot()</code> that uses <code>expr_label()</code> to compute <code>xlim</code> and <code>ylim</code>.</p></li>
 <li><p>Create a simple implementation of <code>mean()</code> that stops with an informative error message if the argument is not numeric:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="kw">c</span>(<span class="st">"a"</span>, <span class="st">"b"</span>, <span class="st">"c"</span>)
+<pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="kw">c</span>(<span class="st">"a"</span>, <span class="st">"b"</span>, <span class="st">"c"</span>)
 <span class="kw">my_mean</span>(x)
 <span class="co">#> Error: `x` is a not a numeric vector.</span>
 <span class="kw">my_mean</span>(x ==<span class="st"> "a"</span>)
 <span class="co">#> Error: `x == "a"` is not a numeric vector.</span>
 <span class="kw">my_mean</span>(<span class="st">"a"</span>)
-<span class="co">#> Error: "a" is not a numeric vector.</span></code></pre></div></li>
+<span class="co">#> Error: "a" is not a numeric vector.</span></code></pre></li>
 <li><p>Read the source code for <code>expr_text()</code>. How does it work? What additional arguments to <code>deparse()</code> does it use?</p></li>
 </ol>
 </div>
@@ -170,7 +152,7 @@ my_label2 <-<span class="st"> </span>function(x) <span class="kw">my_label</s
 <div id="definition-of-a-formula" class="section level3">
 <h3>Definition of a formula</h3>
 <p>Technically, a formula is a “language” object (i.e. an unevaluated expression) with a class of “formula” and an attribute that stores the environment:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span><span class="er">~</span><span class="st"> </span>x +<span class="st"> </span>y +<span class="st"> </span>z
+<pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span><span class="er">~</span><span class="st"> </span>x +<span class="st"> </span>y +<span class="st"> </span>z
 <span class="kw">typeof</span>(f)
 <span class="co">#> [1] "language"</span>
 <span class="kw">attributes</span>(f)
@@ -178,20 +160,20 @@ my_label2 <-<span class="st"> </span>function(x) <span class="kw">my_label</s
 <span class="co">#> [1] "formula"</span>
 <span class="co">#> </span>
 <span class="co">#> $.Environment</span>
-<span class="co">#> <environment: R_GlobalEnv></span></code></pre></div>
+<span class="co">#> <environment: R_GlobalEnv></span></code></pre>
 <p>The structure of the underlying object is slightly different depending on whether you have a one-sided or two-sided formula:</p>
 <ul>
 <li><p>One-sided formulas have length two:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">length</span>(f)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">length</span>(f)
 <span class="co">#> [1] 2</span>
 <span class="co"># The 1st element is always ~</span>
 f[[<span class="dv">1</span>]]
 <span class="co">#> `~`</span>
 <span class="co"># The 2nd element is the RHS</span>
 f[[<span class="dv">2</span>]]
-<span class="co">#> x + y + z</span></code></pre></div></li>
+<span class="co">#> x + y + z</span></code></pre></li>
 <li><p>Two-sided formulas have length three:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">g <-<span class="st"> </span>y ~<span class="st"> </span>x +<span class="st"> </span>z
+<pre class="sourceCode r"><code class="sourceCode r">g <-<span class="st"> </span>y ~<span class="st"> </span>x +<span class="st"> </span>z
 <span class="kw">length</span>(g)
 <span class="co">#> [1] 3</span>
 <span class="co"># The 1st element is still ~</span>
@@ -202,10 +184,10 @@ g[[<span class="dv">2</span>]]
 <span class="co">#> y</span>
 <span class="co"># And the 3rd element is the RHS</span>
 g[[<span class="dv">3</span>]]
-<span class="co">#> x + z</span></code></pre></div></li>
+<span class="co">#> x + z</span></code></pre></li>
 </ul>
 <p>To abstract away these differences, lazyeval provides <code>f_rhs()</code> and <code>f_lhs()</code> to access either side of the formula, and <code>f_env()</code> to access its environment:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_rhs</span>(f)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_rhs</span>(f)
 <span class="co">#> x + y + z</span>
 <span class="kw">f_lhs</span>(f)
 <span class="co">#> NULL</span>
@@ -217,35 +199,35 @@ g[[<span class="dv">3</span>]]
 <span class="kw">f_lhs</span>(g)
 <span class="co">#> y</span>
 <span class="kw">f_env</span>(g)
-<span class="co">#> <environment: R_GlobalEnv></span></code></pre></div>
+<span class="co">#> <environment: R_GlobalEnv></span></code></pre>
 </div>
 <div id="evaluating-a-formula" class="section level3">
 <h3>Evaluating a formula</h3>
 <p>A formula captures delays the evaluation of an expression so you can later evaluate it with <code>f_eval()</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span><span class="er">~</span><span class="st"> </span><span class="dv">1</span> +<span class="st"> </span><span class="dv">2</span> +<span class="st"> </span><span class="dv">3</span>
+<pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span><span class="er">~</span><span class="st"> </span><span class="dv">1</span> +<span class="st"> </span><span class="dv">2</span> +<span class="st"> </span><span class="dv">3</span>
 f
 <span class="co">#> ~1 + 2 + 3</span>
 <span class="kw">f_eval</span>(f)
-<span class="co">#> [1] 6</span></code></pre></div>
+<span class="co">#> [1] 6</span></code></pre>
 <p>This allows you to use a formula as a robust way of delaying evaluation, cleanly separating the creation of the formula from its evaluation. Because formulas capture the code and context, you get the correct result even when a formula is created and evaluated in different places. In the following example, note that the value of <code>x</code> inside <code>add_1000()</code> is used:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">1</span>
+<pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">1</span>
 add_1000 <-<span class="st"> </span>function(x) {
   ~<span class="st"> </span><span class="dv">1000</span> +<span class="st"> </span>x
 }
 
 <span class="kw">add_1000</span>(<span class="dv">3</span>)
 <span class="co">#> ~1000 + x</span>
-<span class="co">#> <environment: 0x7fd4dbeca590></span>
+<span class="co">#> <environment: 0x7fe5890d4190></span>
 <span class="kw">f_eval</span>(<span class="kw">add_1000</span>(<span class="dv">3</span>))
-<span class="co">#> [1] 1003</span></code></pre></div>
+<span class="co">#> [1] 1003</span></code></pre>
 <p>It can be hard to see what’s going on when looking at a formula because important values are stored in the environment, which is largely opaque. You can use <code>f_unwrap()</code> to replace names with their corresponding values:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_unwrap</span>(<span class="kw">add_1000</span>(<span class="dv">3</span>))
-<span class="co">#> ~1000 + 3</span></code></pre></div>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_unwrap</span>(<span class="kw">add_1000</span>(<span class="dv">3</span>))
+<span class="co">#> ~1000 + 3</span></code></pre>
 </div>
 <div id="non-standard-scoping" class="section level3">
 <h3>Non-standard scoping</h3>
 <p><code>f_eval()</code> has an optional second argument: a named list (or data frame) that overrides values found in the formula’s environment.</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">y <-<span class="st"> </span><span class="dv">100</span>
+<pre class="sourceCode r"><code class="sourceCode r">y <-<span class="st"> </span><span class="dv">100</span>
 <span class="kw">f_eval</span>(~<span class="st"> </span>y)
 <span class="co">#> [1] 100</span>
 <span class="kw">f_eval</span>(~<span class="st"> </span>y, <span class="dt">data =</span> <span class="kw">list</span>(<span class="dt">y =</span> <span class="dv">10</span>))
@@ -256,12 +238,12 @@ add_1000 <-<span class="st"> </span>function(x) {
 <span class="co">#> [1] 110</span>
 <span class="co"># Can even supply functions</span>
 <span class="kw">f_eval</span>(~<span class="st"> </span><span class="kw">f</span>(y), <span class="dt">data =</span> <span class="kw">list</span>(<span class="dt">f =</span> function(x) x *<span class="st"> </span><span class="dv">3</span>))
-<span class="co">#> [1] 300</span></code></pre></div>
+<span class="co">#> [1] 300</span></code></pre>
 <p>This makes it very easy to implement non-standard scoping:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_eval</span>(~<span class="st"> </span><span class="kw">mean</span>(cyl), <span class="dt">data =</span> mtcars)
-<span class="co">#> [1] 6.1875</span></code></pre></div>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_eval</span>(~<span class="st"> </span><span class="kw">mean</span>(cyl), <span class="dt">data =</span> mtcars)
+<span class="co">#> [1] 6.1875</span></code></pre>
 <p>One challenge with non-standard scoping is that we’ve introduced some ambiguity. For example, in the code below does <code>x</code> come from <code>mydata</code> or the environment?</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_eval</span>(~<span class="st"> </span>x, <span class="dt">data =</span> mydata)</code></pre></div>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_eval</span>(~<span class="st"> </span>x, <span class="dt">data =</span> mydata)</code></pre>
 <p>You can’t tell without knowing whether or not <code>mydata</code> has a variable called <code>x</code>. To overcome this problem, <code>f_eval()</code> provides two pronouns:</p>
 <ul>
 <li><code>.data</code> is bound to the data frame.</li>
@@ -269,23 +251,23 @@ add_1000 <-<span class="st"> </span>function(x) {
 </ul>
 <p>They both start with <code>.</code> to minimise the chances of clashing with existing variables.</p>
 <p>With these pronouns we can rewrite the previous formula to remove the ambiguity:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">mydata <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">100</span>, <span class="dt">y =</span> <span class="dv">1</span>)
+<pre class="sourceCode r"><code class="sourceCode r">mydata <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">100</span>, <span class="dt">y =</span> <span class="dv">1</span>)
 x <-<span class="st"> </span><span class="dv">10</span>
 
 <span class="kw">f_eval</span>(~<span class="st"> </span>.env$x, <span class="dt">data =</span> mydata)
 <span class="co">#> [1] 10</span>
 <span class="kw">f_eval</span>(~<span class="st"> </span>.data$x, <span class="dt">data =</span> mydata)
-<span class="co">#> [1] 100</span></code></pre></div>
+<span class="co">#> [1] 100</span></code></pre>
 <p>If the variable or object doesn’t exist, you’ll get an informative error:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_eval</span>(~<span class="st"> </span>.env$z, <span class="dt">data =</span> mydata)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_eval</span>(~<span class="st"> </span>.env$z, <span class="dt">data =</span> mydata)
 <span class="co">#> Error: Object 'z' not found in environment</span>
 <span class="kw">f_eval</span>(~<span class="st"> </span>.data$z, <span class="dt">data =</span> mydata)
-<span class="co">#> Error: Variable 'z' not found in data</span></code></pre></div>
+<span class="co">#> Error: Variable 'z' not found in data</span></code></pre>
 </div>
 <div id="unquoting" class="section level3">
 <h3>Unquoting</h3>
 <p><code>f_eval()</code> has one more useful trick up its sleeve: unquoting. Unquoting allows you to write functions where the user supplies part of the formula. For example, the following function allows you to compute the mean of any column (or any function of a column):</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">df_mean <-<span class="st"> </span>function(df, variable) {
+<pre class="sourceCode r"><code class="sourceCode r">df_mean <-<span class="st"> </span>function(df, variable) {
   <span class="kw">f_eval</span>(~<span class="st"> </span><span class="kw">mean</span>(<span class="kw">uq</span>(variable)), <span class="dt">data =</span> df)
 }
 
@@ -294,31 +276,31 @@ x <-<span class="st"> </span><span class="dv">10</span>
 <span class="kw">df_mean</span>(mtcars, ~<span class="st"> </span>disp *<span class="st"> </span><span class="fl">0.01638</span>)
 <span class="co">#> [1] 3.779224</span>
 <span class="kw">df_mean</span>(mtcars, ~<span class="st"> </span><span class="kw">sqrt</span>(mpg))
-<span class="co">#> [1] 4.43477</span></code></pre></div>
+<span class="co">#> [1] 4.43477</span></code></pre>
 <p>To see how this works, we can use <code>f_interp()</code> which <code>f_eval()</code> calls internally (you shouldn’t call it in your own code, but it’s useful for debugging). The key is <code>uq()</code>: <code>uq()</code> evaluates its first (and only) argument and inserts the value into the formula:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">variable <-<span class="st"> </span><span class="er">~</span>cyl
+<pre class="sourceCode r"><code class="sourceCode r">variable <-<span class="st"> </span><span class="er">~</span>cyl
 <span class="kw">f_interp</span>(~<span class="st"> </span><span class="kw">mean</span>(<span class="kw">uq</span>(variable)))
 <span class="co">#> ~mean(cyl)</span>
 
 variable <-<span class="st"> </span><span class="er">~</span><span class="st"> </span>disp *<span class="st"> </span><span class="fl">0.01638</span>
 <span class="kw">f_interp</span>(~<span class="st"> </span><span class="kw">mean</span>(<span class="kw">uq</span>(variable)))
-<span class="co">#> ~mean(disp * 0.01638)</span></code></pre></div>
+<span class="co">#> ~mean(disp * 0.01638)</span></code></pre>
 <p>Unquoting allows you to create code “templates”, where you write most of the expression, while still allowing the user to control important components. You can even use <code>uq()</code> to change the function being called:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span><span class="er">~</span><span class="st"> </span>mean
+<pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span><span class="er">~</span><span class="st"> </span>mean
 <span class="kw">f_interp</span>(~<span class="st"> </span><span class="kw">uq</span>(f)(<span class="kw">uq</span>(variable)))
-<span class="co">#> ~mean(disp * 0.01638)</span></code></pre></div>
+<span class="co">#> ~mean(disp * 0.01638)</span></code></pre>
 <p>Note that <code>uq()</code> only takes the RHS of a formula, which makes it difficult to insert literal formulas into a call:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">formula <-<span class="st"> </span>y ~<span class="st"> </span>x
+<pre class="sourceCode r"><code class="sourceCode r">formula <-<span class="st"> </span>y ~<span class="st"> </span>x
 <span class="kw">f_interp</span>(~<span class="st"> </span><span class="kw">lm</span>(<span class="kw">uq</span>(formula), <span class="dt">data =</span> df))
-<span class="co">#> ~lm(x, data = df)</span></code></pre></div>
+<span class="co">#> ~lm(x, data = df)</span></code></pre>
 <p>You can instead use <code>uqf()</code> which uses the whole formula, not just the RHS:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_interp</span>(~<span class="st"> </span><span class="kw">lm</span>(<span class="kw">uqf</span>(formula), <span class="dt">data =</span> df))
-<span class="co">#> ~lm(y ~ x, data = df)</span></code></pre></div>
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_interp</span>(~<span class="st"> </span><span class="kw">lm</span>(<span class="kw">uqf</span>(formula), <span class="dt">data =</span> df))
+<span class="co">#> ~lm(y ~ x, data = df)</span></code></pre>
 <p>Unquoting is powerful, but it only allows you to modify a single argument: it doesn’t allow you to add an arbitrary number of arguments. To do that, you’ll need “unquote-splice”, or <code>uqs()</code>. The first (and only) argument to <code>uqs()</code> should be a list of arguments to be spliced into the call:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">variable <-<span class="st"> </span><span class="er">~</span><span class="st"> </span>x
+<pre class="sourceCode r"><code class="sourceCode r">variable <-<span class="st"> </span><span class="er">~</span><span class="st"> </span>x
 extra_args <-<span class="st"> </span><span class="kw">list</span>(<span class="dt">na.rm =</span> <span class="ot">TRUE</span>, <span class="dt">trim =</span> <span class="fl">0.9</span>)
 <span class="kw">f_interp</span>(~<span class="st"> </span><span class="kw">mean</span>(<span class="kw">uq</span>(variable), <span class="kw">uqs</span>(extra_args)))
-<span class="co">#> ~mean(x, na.rm = TRUE, trim = 0.9)</span></code></pre></div>
+<span class="co">#> ~mean(x, na.rm = TRUE, trim = 0.9)</span></code></pre>
 </div>
 <div id="exercises-1" class="section level3">
 <h3>Exercises</h3>
@@ -326,9 +308,9 @@ extra_args <-<span class="st"> </span><span class="kw">list</span>(<span clas
 <li><p>Create a wrapper around <code>lm()</code> that allows the user to supply the response and predictors as two separate formulas.</p></li>
 <li><p>Compare and contrast <code>f_eval()</code> with <code>with()</code>.</p></li>
 <li><p>Why does this code work even though <code>f</code> is defined in two places? (And one of them is not a function).</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span>function(x) x +<span class="st"> </span><span class="dv">1</span>
+<pre class="sourceCode r"><code class="sourceCode r">f <-<span class="st"> </span>function(x) x +<span class="st"> </span><span class="dv">1</span>
 <span class="kw">f_eval</span>(~<span class="st"> </span><span class="kw">f</span>(<span class="dv">10</span>), <span class="kw">list</span>(<span class="dt">f =</span> <span class="st">"a"</span>))
-<span class="co">#> [1] 11</span></code></pre></div></li>
+<span class="co">#> [1] 11</span></code></pre></li>
 </ol>
 </div>
 </div>
@@ -348,7 +330,7 @@ extra_args <-<span class="st"> </span><span class="kw">list</span>(<span clas
 <li><p>It always returns a data frame.</p></li>
 </ol>
 <p>The implementation of <code>sieve()</code> is straightforward. First we use <code>f_eval()</code> to perform NSS. Then we then check that we have a logical vector, replace <code>NA</code>s with <code>FALSE</code>, and subset with <code>[</code>.</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">sieve <-<span class="st"> </span>function(df, condition) {
+<pre class="sourceCode r"><code class="sourceCode r">sieve <-<span class="st"> </span>function(df, condition) {
   rows <-<span class="st"> </span><span class="kw">f_eval</span>(condition, df)
   if (!<span class="kw">is.logical</span>(rows)) {
     <span class="kw">stop</span>(<span class="st">"`condition` must be logical."</span>, <span class="dt">call. =</span> <span class="ot">FALSE</span>)
@@ -365,32 +347,32 @@ df <-<span class="st"> </span><span class="kw">data.frame</span>(<span class=
 <span class="co">#> 2 2 4</span>
 <span class="kw">sieve</span>(df, ~<span class="st"> </span>x ==<span class="st"> </span>y)
 <span class="co">#>   x y</span>
-<span class="co">#> 3 3 3</span></code></pre></div>
+<span class="co">#> 3 3 3</span></code></pre>
 <div id="programming-with-sieve" class="section level3">
 <h3>Programming with <code>sieve()</code></h3>
 <p>Imagine that you’ve written some code that looks like this:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">sieve</span>(march, ~<span class="st"> </span>x ><span class="st"> </span><span class="dv">100</span>)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">sieve</span>(march, ~<span class="st"> </span>x ><span class="st"> </span><span class="dv">100</span>)
 <span class="kw">sieve</span>(april, ~<span class="st"> </span>x ><span class="st"> </span><span class="dv">50</span>)
 <span class="kw">sieve</span>(june, ~<span class="st"> </span>x ><span class="st"> </span><span class="dv">45</span>)
-<span class="kw">sieve</span>(july, ~<span class="st"> </span>x ><span class="st"> </span><span class="dv">17</span>)</code></pre></div>
+<span class="kw">sieve</span>(july, ~<span class="st"> </span>x ><span class="st"> </span><span class="dv">17</span>)</code></pre>
 <p>(This is a contrived example, but it illustrates all of the important issues you’ll need to consider when writing more useful functions.)</p>
 <p>Instead of continuing to copy-and-paste your code, you decide to wrap up the common behaviour in a function:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">threshold_x <-<span class="st"> </span>function(df, threshold) {
+<pre class="sourceCode r"><code class="sourceCode r">threshold_x <-<span class="st"> </span>function(df, threshold) {
   <span class="kw">sieve</span>(df, ~<span class="st"> </span>x ><span class="st"> </span>threshold)
 }
 <span class="kw">threshold_x</span>(df, <span class="dv">3</span>)
 <span class="co">#>   x y</span>
 <span class="co">#> 4 4 2</span>
-<span class="co">#> 5 5 1</span></code></pre></div>
+<span class="co">#> 5 5 1</span></code></pre>
 <p>There are two ways that this function might fail:</p>
 <ol style="list-style-type: decimal">
 <li><p>The data frame might not have a variable called <code>x</code>. This will fail unless there’s a variable called <code>x</code> hanging around in the global environment:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">rm</span>(x)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">rm</span>(x)
 df2 <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">y =</span> <span class="dv">5</span>:<span class="dv">1</span>)
 
 <span class="co"># Throws an error</span>
 <span class="kw">threshold_x</span>(df2, <span class="dv">3</span>)
-<span class="co">#> Error in eval(expr, envir, enclos): object 'x' not found</span>
+<span class="co">#> Error in eval(expr, data, expr_env): object 'x' not found</span>
 
 <span class="co"># Silently gives the incorrect result!</span>
 x <-<span class="st"> </span><span class="dv">5</span>
@@ -400,16 +382,16 @@ x <-<span class="st"> </span><span class="dv">5</span>
 <span class="co">#> 2 4</span>
 <span class="co">#> 3 3</span>
 <span class="co">#> 4 2</span>
-<span class="co">#> 5 1</span></code></pre></div></li>
+<span class="co">#> 5 1</span></code></pre></li>
 <li><p>The data frame might have a variable called <code>threshold</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">df3 <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">1</span>:<span class="dv">5</span>, <span class="dt">y =</span> <span class="dv">5</span>:<span class="dv">1</span>, <span class="dt">threshold =</span> <span class="dv">4</span>)
+<pre class="sourceCode r"><code class="sourceCode r">df3 <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">1</span>:<span class="dv">5</span>, <span class="dt">y =</span> <span class="dv">5</span>:<span class="dv">1</span>, <span class="dt">threshold =</span> <span class="dv">4</span>)
 <span class="kw">threshold_x</span>(df3, <span class="dv">3</span>)
 <span class="co">#>   x y threshold</span>
-<span class="co">#> 5 5 1         4</span></code></pre></div></li>
+<span class="co">#> 5 5 1         4</span></code></pre></li>
 </ol>
 <p>These failures are partiuclarly pernicious because instead of throwing an error they silently produce the wrong answer. Both failures arise because <code>f_eval()</code> introduces ambiguity by looking in two places for each name: the supplied data and formula environment.</p>
 <p>To make <code>threshold_x()</code> more reliable, we need to be more explicit by using the <code>.data</code> and <code>.env</code> pronouns:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">threshold_x <-<span class="st"> </span>function(df, threshold) {
+<pre class="sourceCode r"><code class="sourceCode r">threshold_x <-<span class="st"> </span>function(df, threshold) {
   <span class="kw">sieve</span>(df, ~<span class="st"> </span>.data$x ><span class="st"> </span>.env$threshold)
 }
 
@@ -418,24 +400,24 @@ x <-<span class="st"> </span><span class="dv">5</span>
 <span class="kw">threshold_x</span>(df3, <span class="dv">3</span>)
 <span class="co">#>   x y threshold</span>
 <span class="co">#> 4 4 2         4</span>
-<span class="co">#> 5 5 1         4</span></code></pre></div>
+<span class="co">#> 5 5 1         4</span></code></pre>
 <p>Here <code>.env</code> is bound to the environment where <code>~</code> is evaluated, namely the inside of <code>threshold_x()</code>.</p>
 </div>
 <div id="adding-arguments" class="section level3">
 <h3>Adding arguments</h3>
 <p>The <code>threshold_x()</code> function is not very useful because it’s bound to a specific variable. It would be more powerful if we could vary both the threshold and the variable it applies to. We can do that by taking an additional argument to specify which variable to use.</p>
 <p>One simple approach is to use a string and <code>[[</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">threshold <-<span class="st"> </span>function(df, variable, threshold) {
+<pre class="sourceCode r"><code class="sourceCode r">threshold <-<span class="st"> </span>function(df, variable, threshold) {
   <span class="kw">stopifnot</span>(<span class="kw">is.character</span>(variable), <span class="kw">length</span>(variable) ==<span class="st"> </span><span class="dv">1</span>)
   
   <span class="kw">sieve</span>(df, ~<span class="st"> </span>.data[[.env$variable]] ><span class="st"> </span>.env$threshold)
 }
 <span class="kw">threshold</span>(df, <span class="st">"x"</span>, <span class="dv">4</span>)
 <span class="co">#>   x y</span>
-<span class="co">#> 5 5 1</span></code></pre></div>
+<span class="co">#> 5 5 1</span></code></pre>
 <p>This is a simple and robust solution, but only allows us to use an existing variable, not an arbitrary expression like <code>sqrt(x)</code>.</p>
 <p>A more general solution is to allow the user to supply a formula, and use unquoting:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">threshold <-<span class="st"> </span>function(df, <span class="dt">variable =</span> ~x, <span class="dt">threshold =</span> <span class="dv">0</span>) {
+<pre class="sourceCode r"><code class="sourceCode r">threshold <-<span class="st"> </span>function(df, <span class="dt">variable =</span> ~x, <span class="dt">threshold =</span> <span class="dv">0</span>) {
   <span class="kw">sieve</span>(df, ~<span class="st"> </span><span class="kw">uq</span>(variable) ><span class="st"> </span>.env$threshold)
 }
 
@@ -445,18 +427,18 @@ x <-<span class="st"> </span><span class="dv">5</span>
 <span class="kw">threshold</span>(df, ~<span class="st"> </span><span class="kw">abs</span>(x -<span class="st"> </span>y), <span class="dv">2</span>)
 <span class="co">#>   x y</span>
 <span class="co">#> 1 1 5</span>
-<span class="co">#> 5 5 1</span></code></pre></div>
+<span class="co">#> 5 5 1</span></code></pre>
 <p>In this case, it’s the responsibility of the user to ensure the <code>variable</code> is specified unambiguously. <code>f_eval()</code> is designed so that <code>.data</code> and <code>.env</code> work even when evaluated inside of <code>uq()</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">3</span>
+<pre class="sourceCode r"><code class="sourceCode r">x <-<span class="st"> </span><span class="dv">3</span>
 <span class="kw">threshold</span>(df, ~<span class="st"> </span>.data$x -<span class="st"> </span>.env$x, <span class="dv">0</span>)
 <span class="co">#>   x y</span>
 <span class="co">#> 4 4 2</span>
-<span class="co">#> 5 5 1</span></code></pre></div>
+<span class="co">#> 5 5 1</span></code></pre>
 </div>
 <div id="dot-dot-dot" class="section level3">
 <h3>Dot-dot-dot</h3>
 <p>There is one more tool that you might find useful for functions that take <code>...</code>. For example, the code below implements a function similar to <code>dplyr::mutate()</code> or <code>base::transform()</code>.</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">mogrify <-<span class="st"> </span>function(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, ...) {
+<pre class="sourceCode r"><code class="sourceCode r">mogrify <-<span class="st"> </span>function(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, ...) {
   args <-<span class="st"> </span><span class="kw">list</span>(...)
   
   for (nm in <span class="kw">names</span>(args)) {
@@ -464,37 +446,37 @@ x <-<span class="st"> </span><span class="dv">5</span>
   }
   
   <span class="st">`</span><span class="dt">_df</span><span class="st">`</span>
-}</code></pre></div>
+}</code></pre>
 <p>(NB: the first argument is a non-syntactic name (i.e. it requires quoting with <code>`</code>) so it doesn’t accidentally match one of the names of the new variables.)</p>
 <p><code>transmogrifty()</code> makes it easy to add new variables to a data frame:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">df <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">1</span>:<span class="dv">5</span>, <span class="dt">y =</span> <span class="kw">sample</span>(<span class="dv">5</span>))
+<pre class="sourceCode r"><code class="sourceCode r">df <-<span class="st"> </span><span class="kw">data.frame</span>(<span class="dt">x =</span> <span class="dv">1</span>:<span class="dv">5</span>, <span class="dt">y =</span> <span class="kw">sample</span>(<span class="dv">5</span>))
 <span class="kw">mogrify</span>(df, <span class="dt">z =</span> ~<span class="st"> </span>x +<span class="st"> </span>y, <span class="dt">z2 =</span> ~<span class="st"> </span>z *<span class="st"> </span><span class="dv">2</span>)
 <span class="co">#>   x y z z2</span>
 <span class="co">#> 1 1 3 4  8</span>
 <span class="co">#> 2 2 4 6 12</span>
-<span class="co">#> 3 3 2 5 10</span>
+<span class="co">#> 3 3 1 4  8</span>
 <span class="co">#> 4 4 5 9 18</span>
-<span class="co">#> 5 5 1 6 12</span></code></pre></div>
+<span class="co">#> 5 5 2 7 14</span></code></pre>
 <p>One problem with this implementation is that it’s hard to specify the names of the generated variables. Imagine you want a function where the name and expression are in separate variables. This is awkward because the variable name is supplied as an argument name to <code>mogrify()</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">add_variable <-<span class="st"> </span>function(df, name, expr) {
+<pre class="sourceCode r"><code class="sourceCode r">add_variable <-<span class="st"> </span>function(df, name, expr) {
   <span class="kw">do.call</span>(<span class="st">"mogrify"</span>, <span class="kw">c</span>(<span class="kw">list</span>(df), <span class="kw">setNames</span>(<span class="kw">list</span>(expr), name)))
 }
 <span class="kw">add_variable</span>(df, <span class="st">"z"</span>, ~<span class="st"> </span>x +<span class="st"> </span>y)
 <span class="co">#>   x y z</span>
 <span class="co">#> 1 1 3 4</span>
 <span class="co">#> 2 2 4 6</span>
-<span class="co">#> 3 3 2 5</span>
+<span class="co">#> 3 3 1 4</span>
 <span class="co">#> 4 4 5 9</span>
-<span class="co">#> 5 5 1 6</span></code></pre></div>
+<span class="co">#> 5 5 2 7</span></code></pre>
 <p>Lazyeval provides the <code>f_list()</code> function to make writing this sort of function a little easier. It takes a list of formulas and evaluates the LHS of each formula (if present) to rename the elements:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_list</span>(<span class="st">"x"</span> ~<span class="st"> </span>y, <span class="dt">z =</span> ~z)
+<pre class="sourceCode r"><code class="sourceCode r"><span class="kw">f_list</span>(<span class="st">"x"</span> ~<span class="st"> </span>y, <span class="dt">z =</span> ~z)
 <span class="co">#> $x</span>
 <span class="co">#> ~y</span>
 <span class="co">#> </span>
 <span class="co">#> $z</span>
-<span class="co">#> ~z</span></code></pre></div>
+<span class="co">#> ~z</span></code></pre>
 <p>If we tweak <code>mogrify()</code> to use <code>f_list()</code> instead of <code>list()</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">mogrify <-<span class="st"> </span>function(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, ...) {
+<pre class="sourceCode r"><code class="sourceCode r">mogrify <-<span class="st"> </span>function(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, ...) {
   args <-<span class="st"> </span><span class="kw">f_list</span>(...)
   
   for (nm in <span class="kw">names</span>(args)) {
@@ -502,18 +484,18 @@ x <-<span class="st"> </span><span class="dv">5</span>
   }
   
   <span class="st">`</span><span class="dt">_df</span><span class="st">`</span>
-}</code></pre></div>
+}</code></pre>
 <p><code>add_new()</code> becomes much simpler:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">add_variable <-<span class="st"> </span>function(df, name, expr) {
+<pre class="sourceCode r"><code class="sourceCode r">add_variable <-<span class="st"> </span>function(df, name, expr) {
   <span class="kw">mogrify</span>(df, name ~<span class="st"> </span><span class="kw">uq</span>(expr))
 }
 <span class="kw">add_variable</span>(df, <span class="st">"z"</span>, ~<span class="st"> </span>x +<span class="st"> </span>y)
 <span class="co">#>   x y z</span>
 <span class="co">#> 1 1 3 4</span>
 <span class="co">#> 2 2 4 6</span>
-<span class="co">#> 3 3 2 5</span>
+<span class="co">#> 3 3 1 4</span>
 <span class="co">#> 4 4 5 9</span>
-<span class="co">#> 5 5 1 6</span></code></pre></div>
+<span class="co">#> 5 5 2 7</span></code></pre>
 </div>
 <div id="exercises-2" class="section level3">
 <h3>Exercises</h3>
@@ -527,7 +509,7 @@ x <-<span class="st"> </span><span class="dv">5</span>
 <h2>Non-standard evaluation</h2>
 <p>In some situations you might want to eliminate the formula altogether, and allow the user to type expressions directly. I was once much enamoured with this approach (witness ggplot2, dplyr, …). However, I now think that it should be used sparingly because explict quoting with <code>~</code> leads to simpler code, and makes it more clear to the user that something special is going on.</p>
 <p>That said, lazyeval does allow you to eliminate the <code>~</code> if you really want to. In this case, I recommend having both a NSE and SE version of the function. The SE version, which takes formuals, should have suffix <code>_</code>:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">sieve_ <-<span class="st"> </span>function(df, condition) {
+<pre class="sourceCode r"><code class="sourceCode r">sieve_ <-<span class="st"> </span>function(df, condition) {
   rows <-<span class="st"> </span><span class="kw">f_eval</span>(condition, df)
   if (!<span class="kw">is.logical</span>(rows)) {
     <span class="kw">stop</span>(<span class="st">"`condition` must be logical."</span>, <span class="dt">call. =</span> <span class="ot">FALSE</span>)
@@ -535,16 +517,16 @@ x <-<span class="st"> </span><span class="dv">5</span>
   
   rows[<span class="kw">is.na</span>(rows)] <-<span class="st"> </span><span class="ot">FALSE</span>
   df[rows, , drop =<span class="st"> </span><span class="ot">FALSE</span>]
-}</code></pre></div>
+}</code></pre>
 <p>Then create the NSE version which doesn’t need the explicit formula. The key is the use of <code>f_capture()</code> which takes an unevaluated argument (a promise) and captures it as a formula:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">sieve <-<span class="st"> </span>function(df, expr) {
+<pre class="sourceCode r"><code class="sourceCode r">sieve <-<span class="st"> </span>function(df, expr) {
   <span class="kw">sieve_</span>(df, <span class="kw">f_capture</span>(expr))
 }
 <span class="kw">sieve</span>(df, x ==<span class="st"> </span><span class="dv">1</span>)
 <span class="co">#>   x y</span>
-<span class="co">#> 1 1 3</span></code></pre></div>
+<span class="co">#> 1 1 3</span></code></pre>
 <p>If you’re familiar with <code>substitute()</code> you might expect the same drawbacks to apply. However, <code>f_capture()</code> is smart enough to follow a chain of promises back to the original value, so, for example, this code works fine:</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">scramble <-<span class="st"> </span>function(df) {
+<pre class="sourceCode r"><code class="sourceCode r">scramble <-<span class="st"> </span>function(df) {
   df[<span class="kw">sample</span>(<span class="kw">nrow</span>(df)), , drop =<span class="st"> </span><span class="ot">FALSE</span>]
 }
 subscramble <-<span class="st"> </span>function(df, expr) {
@@ -552,13 +534,13 @@ subscramble <-<span class="st"> </span>function(df, expr) {
 }
 <span class="kw">subscramble</span>(df, x <<span class="st"> </span><span class="dv">4</span>)
 <span class="co">#>   x y</span>
+<span class="co">#> 3 3 1</span>
 <span class="co">#> 2 2 4</span>
-<span class="co">#> 3 3 2</span>
-<span class="co">#> 1 1 3</span></code></pre></div>
+<span class="co">#> 1 1 3</span></code></pre>
 <div id="dot-dot-dot-1" class="section level3">
 <h3>Dot-dot-dot</h3>
 <p>If you want a <code>...</code> function that doesn’t require formulas, I recommend that the SE version take a list of arguments, and the NSE version uses <code>dots_capture()</code> to capture multiple arguments as a list of formulas.</p>
-<div class="sourceCode"><pre class="sourceCode r"><code class="sourceCode r">mogrify_ <-<span class="st"> </span>function(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, args) {
+<pre class="sourceCode r"><code class="sourceCode r">mogrify_ <-<span class="st"> </span>function(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, args) {
   args <-<span class="st"> </span><span class="kw">as_f_list</span>(args)
   
   for (nm in <span class="kw">names</span>(args)) {
@@ -570,7 +552,7 @@ subscramble <-<span class="st"> </span>function(df, expr) {
 
 mogrify <-<span class="st"> </span>function(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, ...) {
   <span class="kw">mogrify_</span>(<span class="st">`</span><span class="dt">_df</span><span class="st">`</span>, <span class="kw">dots_capture</span>(...))
-}</code></pre></div>
+}</code></pre>
 </div>
 <div id="exercises-3" class="section level3">
 <h3>Exercises</h3>
@@ -597,7 +579,7 @@ mogrify <-<span class="st"> </span>function(<span class="st">`</span><span cl
   (function () {
     var script = document.createElement("script");
     script.type = "text/javascript";
-    script.src  = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
+    script.src  = "https://mathjax.rstudio.com/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
     document.getElementsByTagName("head")[0].appendChild(script);
   })();
 </script>
diff --git a/man/all_dots.Rd b/man/all_dots.Rd
index 77beb12..d98d889 100644
--- a/man/all_dots.Rd
+++ b/man/all_dots.Rd
@@ -21,4 +21,3 @@ A \code{\link{lazy_dots}}
 Combine explicit and implicit dots.
 }
 \keyword{internal}
-
diff --git a/man/as.lazy.Rd b/man/as.lazy.Rd
index 2ae4d87..64a6089 100644
--- a/man/as.lazy.Rd
+++ b/man/as.lazy.Rd
@@ -33,4 +33,3 @@ as.lazy_dots(quote(x), globalenv())
 as.lazy_dots(quote(f()), globalenv())
 as.lazy_dots(lazy(x))
 }
-
diff --git a/man/as_name.Rd b/man/as_name.Rd
index cb95304..d4c7205 100644
--- a/man/as_name.Rd
+++ b/man/as_name.Rd
@@ -1,8 +1,8 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/language.R
 \name{as_name}
-\alias{as_call}
 \alias{as_name}
+\alias{as_call}
 \title{Coerce an object to a name or call.}
 \usage{
 as_name(x)
@@ -25,4 +25,3 @@ as_call("x + y")
 as_call(~ f)
 as_name(~ f())
 }
-
diff --git a/man/ast_.Rd b/man/ast_.Rd
index dc75f85..a141d46 100644
--- a/man/ast_.Rd
+++ b/man/ast_.Rd
@@ -1,8 +1,8 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/ast.R
 \name{ast_}
-\alias{ast}
 \alias{ast_}
+\alias{ast}
 \title{Display a call (or expression) as a tree.}
 \usage{
 ast_(x, width = getOption("width"))
@@ -29,4 +29,3 @@ ast_(quote(f(x, 1, g(), h(i()))))
 ast_(quote(if (TRUE) 3 else 4))
 ast_(expression(1, 2, 3))
 }
-
diff --git a/man/auto_name.Rd b/man/auto_name.Rd
index 5c0aae0..56c239d 100644
--- a/man/auto_name.Rd
+++ b/man/auto_name.Rd
@@ -22,4 +22,3 @@ auto_name(x)
 auto_name(list(~f, quote(x)))
 }
 \keyword{internal}
-
diff --git a/man/call_modify.Rd b/man/call_modify.Rd
index 010b112..fe17b4d 100644
--- a/man/call_modify.Rd
+++ b/man/call_modify.Rd
@@ -38,4 +38,3 @@ call_modify(call, list(trim = 0.1))
 # Add an explicit missing argument
 call_modify(call, list(na.rm = quote(expr = )))
 }
-
diff --git a/man/call_new.Rd b/man/call_new.Rd
index b13ac49..ecbd4a0 100644
--- a/man/call_new.Rd
+++ b/man/call_new.Rd
@@ -25,4 +25,3 @@ call_new(quote(f()), a = 1)
 call_new(quote(f), a = 1, b = 2)
 call_new(quote(f), .args = list(a = 1, b = 2))
 }
-
diff --git a/man/common_env.Rd b/man/common_env.Rd
index e098cf4..0896052 100644
--- a/man/common_env.Rd
+++ b/man/common_env.Rd
@@ -20,4 +20,3 @@ common_env(list(f(1)))
 common_env(list(f(1), f(2)))
 }
 \keyword{internal}
-
diff --git a/man/expr_label.Rd b/man/expr_label.Rd
index 21a6c28..1b3d6cd 100644
--- a/man/expr_label.Rd
+++ b/man/expr_label.Rd
@@ -1,10 +1,10 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/expr.R
 \name{expr_label}
-\alias{expr_env}
-\alias{expr_find}
 \alias{expr_label}
 \alias{expr_text}
+\alias{expr_find}
+\alias{expr_env}
 \title{Find the expression associated with an argument}
 \usage{
 expr_label(x)
@@ -56,4 +56,3 @@ expr_label(foo({
   print(x)
 }))
 }
-
diff --git a/man/f_capture.Rd b/man/f_capture.Rd
index 1f63a46..094b0c5 100644
--- a/man/f_capture.Rd
+++ b/man/f_capture.Rd
@@ -1,8 +1,8 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/f-capture.R
 \name{f_capture}
-\alias{dots_capture}
 \alias{f_capture}
+\alias{dots_capture}
 \title{Make a promise explicit by converting into a formula.}
 \usage{
 f_capture(x)
@@ -37,4 +37,3 @@ g <- function(y) h(y)
 h <- function(z) f_capture(z)
 f(a + b + c)
 }
-
diff --git a/man/f_eval.Rd b/man/f_eval.Rd
index b7ad356..f5816b4 100644
--- a/man/f_eval.Rd
+++ b/man/f_eval.Rd
@@ -1,9 +1,9 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/f-eval.R
 \name{f_eval_rhs}
-\alias{f_eval}
-\alias{f_eval_lhs}
 \alias{f_eval_rhs}
+\alias{f_eval_lhs}
+\alias{f_eval}
 \alias{find_data}
 \title{Evaluate a formula}
 \usage{
@@ -43,6 +43,7 @@ possible to be explicit about where you want values to come from:
 \code{.env} and \code{.data}. These are thin wrappers around \code{.data}
 and \code{.env} that throw errors if you try to access non-existent values.
 }
+
 \examples{
 f_eval(~ 1 + 2 + 3)
 
@@ -72,4 +73,3 @@ f_eval(~ mean(cyl), mtcars)
 var <- ~ cyl
 f_eval(~ mean( uq(var) ), mtcars)
 }
-
diff --git a/man/f_interp.Rd b/man/f_interp.Rd
index 155452d..d165855 100644
--- a/man/f_interp.Rd
+++ b/man/f_interp.Rd
@@ -3,6 +3,8 @@
 \name{f_interp}
 \alias{f_interp}
 \alias{uq}
+\alias{uqs}
+\alias{uq}
 \alias{uqf}
 \alias{uqs}
 \title{Interpolate a formula}
@@ -37,6 +39,7 @@ These terms have a rich history in LISP, and live on in modern languages
 like \href{Julia}{http://docs.julialang.org/en/release-0.1/manual/metaprogramming/}
 and \href{Racket}{https://docs.racket-lang.org/reference/quasiquote.html}.
 }
+
 \examples{
 f_interp(x ~ 1 + uq(1 + 2 + 3) + 10)
 
@@ -57,4 +60,3 @@ f <- foo(10)
 f
 f_interp(f)
 }
-
diff --git a/man/f_list.Rd b/man/f_list.Rd
index b900ced..9568d37 100644
--- a/man/f_list.Rd
+++ b/man/f_list.Rd
@@ -1,8 +1,8 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/formula.R
 \name{f_list}
-\alias{as_f_list}
 \alias{f_list}
+\alias{as_f_list}
 \title{Build a named list from the LHS of formulas}
 \usage{
 f_list(...)
@@ -26,4 +26,3 @@ current name with the result.
 f_list("y" ~ x)
 f_list(a = "y" ~ a, ~ b, c = ~c)
 }
-
diff --git a/man/f_new.Rd b/man/f_new.Rd
index 91140e2..c597900 100644
--- a/man/f_new.Rd
+++ b/man/f_new.Rd
@@ -21,4 +21,3 @@ Create a formula object by "hand".
 f_new(quote(a))
 f_new(quote(a), quote(b))
 }
-
diff --git a/man/f_rhs.Rd b/man/f_rhs.Rd
index 850e13a..ba9349b 100644
--- a/man/f_rhs.Rd
+++ b/man/f_rhs.Rd
@@ -1,12 +1,12 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/formula.R
 \name{f_rhs}
-\alias{f_env}
-\alias{f_env<-}
-\alias{f_lhs}
-\alias{f_lhs<-}
 \alias{f_rhs}
 \alias{f_rhs<-}
+\alias{f_lhs}
+\alias{f_lhs<-}
+\alias{f_env}
+\alias{f_env<-}
 \title{Get/set formula components.}
 \usage{
 f_rhs(f)
@@ -47,4 +47,3 @@ f_lhs(x ~ y)
 
 f_env(~ x)
 }
-
diff --git a/man/f_text.Rd b/man/f_text.Rd
index de38c1d..6c4178f 100644
--- a/man/f_text.Rd
+++ b/man/f_text.Rd
@@ -1,8 +1,8 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/formula.R
 \name{f_text}
-\alias{f_label}
 \alias{f_text}
+\alias{f_label}
 \title{Turn RHS of formula into a string/label.}
 \usage{
 f_text(x, width = 60L, nlines = Inf)
@@ -35,4 +35,3 @@ f_label(~ foo({
   print(x)
 }))
 }
-
diff --git a/man/f_unwrap.Rd b/man/f_unwrap.Rd
index 1bab013..9095e1a 100644
--- a/man/f_unwrap.Rd
+++ b/man/f_unwrap.Rd
@@ -18,4 +18,3 @@ n <- 100
 f <- ~ x + n
 f_unwrap(f)
 }
-
diff --git a/man/function_new.Rd b/man/function_new.Rd
index 768dafe..d04bf7b 100644
--- a/man/function_new.Rd
+++ b/man/function_new.Rd
@@ -37,4 +37,3 @@ attr(f, "srcref") <- NULL
 # Now they are:
 stopifnot(identical(f, g))
 }
-
diff --git a/man/interp.Rd b/man/interp.Rd
index d5a828b..7245b81 100644
--- a/man/interp.Rd
+++ b/man/interp.Rd
@@ -44,4 +44,3 @@ interp(~ x + y, .values = list(x = 10))
 y <- 10
 interp(~ x + y, .values = environment())
 }
-
diff --git a/man/is_formula.Rd b/man/is_formula.Rd
index 4bd36c8..f741ea7 100644
--- a/man/is_formula.Rd
+++ b/man/is_formula.Rd
@@ -16,4 +16,3 @@ Is object a formula?
 is_formula(~ 10)
 is_formula(10)
 }
-
diff --git a/man/is_lang.Rd b/man/is_lang.Rd
index da2de4b..c201008 100644
--- a/man/is_lang.Rd
+++ b/man/is_lang.Rd
@@ -1,11 +1,11 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/language.R
 \name{is_lang}
-\alias{is_atomic}
-\alias{is_call}
 \alias{is_lang}
 \alias{is_name}
+\alias{is_call}
 \alias{is_pairlist}
+\alias{is_atomic}
 \title{Is an object a language object?}
 \usage{
 is_lang(x)
@@ -43,4 +43,3 @@ is_call(q3)
 \code{\link{as_name}()} and \code{\link{as_call}()} for coercion
   functions.
 }
-
diff --git a/man/lazy_.Rd b/man/lazy_.Rd
index 87ba54d..59d34a2 100644
--- a/man/lazy_.Rd
+++ b/man/lazy_.Rd
@@ -1,8 +1,8 @@
 % Generated by roxygen2: do not edit by hand
 % Please edit documentation in R/lazy.R
 \name{lazy_}
-\alias{lazy}
 \alias{lazy_}
+\alias{lazy}
 \title{Capture expression for later lazy evaluation.}
 \usage{
 lazy_(expr, env)
@@ -55,4 +55,3 @@ h(a + b)
 # To avoid this behavour, set .follow_symbols = FALSE
 # See vignette("chained-promises") for details
 }
-
diff --git a/man/lazy_dots.Rd b/man/lazy_dots.Rd
index 8e68e55..fcbd48a 100644
--- a/man/lazy_dots.Rd
+++ b/man/lazy_dots.Rd
@@ -44,4 +44,3 @@ l["z"] <- list(~g)
 
 c(lazy_dots(x = 1), lazy_dots(f))
 }
-
diff --git a/man/lazy_eval.Rd b/man/lazy_eval.Rd
index a040258..f5cb7c9 100644
--- a/man/lazy_eval.Rd
+++ b/man/lazy_eval.Rd
@@ -28,4 +28,3 @@ lazy_eval(f(10), list(x = 1, z = 1))
 
 lazy_eval(lazy_dots(a = x, b = z), list(x = 10))
 }
-
diff --git a/man/make_call.Rd b/man/make_call.Rd
index df53ee8..5c7ff62 100644
--- a/man/make_call.Rd
+++ b/man/make_call.Rd
@@ -31,4 +31,3 @@ make_call(quote(f), ~x)
 # If no known or no common environment, fails back to baseenv()
 make_call(quote(f), quote(x))
 }
-
diff --git a/man/missing_arg.Rd b/man/missing_arg.Rd
index 1246952..e2655eb 100644
--- a/man/missing_arg.Rd
+++ b/man/missing_arg.Rd
@@ -13,4 +13,3 @@ Generate a missing argument.
 f_interp(~f(x = uq(missing_arg())))
 f_interp(~f(x = uq(NULL)))
 }
-
diff --git a/src/expr.c b/src/expr.c
index 2c7ec1e..b8e0584 100644
--- a/src/expr.c
+++ b/src/expr.c
@@ -70,7 +70,7 @@ SEXP expr_find_(SEXP name, SEXP env) {
   return base_promise(promise, env);
 }
 
-SEXP expr_env_(SEXP name, SEXP env, SEXP env_default) {
+SEXP expr_env_(SEXP name, SEXP env) {
   SEXP promise = Rf_findVar(name, env);
   return base_promise_env(promise, env);
 }
diff --git a/src/init.c b/src/init.c
new file mode 100644
index 0000000..f653b53
--- /dev/null
+++ b/src/init.c
@@ -0,0 +1,30 @@
+#include <Rinternals.h>
+#include <R_ext/Rdynload.h>
+
+extern SEXP env(SEXP);
+extern SEXP expr_env_(SEXP, SEXP);
+extern SEXP expr_find_(SEXP, SEXP);
+extern SEXP interp_(SEXP, SEXP, SEXP);
+extern SEXP lhs(SEXP);
+extern SEXP lhs_name(SEXP);
+extern SEXP make_lazy(SEXP, SEXP, SEXP);
+extern SEXP make_lazy_dots(SEXP, SEXP, SEXP);
+extern SEXP rhs(SEXP);
+
+static const R_CallMethodDef call_entries[] = {
+  {"lazyeval_env",                  (DL_FUNC) &env, 1},
+  {"lazyeval_expr_env_",            (DL_FUNC) &expr_env_, 2},
+  {"lazyeval_expr_find_",           (DL_FUNC) &expr_find_, 2},
+  {"lazyeval_interp_",              (DL_FUNC) &interp_, 3},
+  {"lazyeval_lhs",                  (DL_FUNC) &lhs, 1},
+  {"lazyeval_lhs_name",             (DL_FUNC) &lhs_name, 1},
+  {"lazyeval_make_lazy",            (DL_FUNC) &make_lazy, 3},
+  {"lazyeval_make_lazy_dots",       (DL_FUNC) &make_lazy_dots, 3},
+  {"lazyeval_rhs",                  (DL_FUNC) &rhs, 1},
+  {NULL, NULL, 0}
+};
+
+void R_init_lazyeval(DllInfo* dll) {
+  R_registerRoutines(dll, NULL, call_entries, NULL, NULL);
+  R_useDynamicSymbols(dll, FALSE);
+}
diff --git a/src/lazy.c b/src/lazy.c
index 98883f8..d0b9d70 100644
--- a/src/lazy.c
+++ b/src/lazy.c
@@ -30,8 +30,7 @@ SEXP promise_as_lazy(SEXP promise, SEXP env, int follow_symbols) {
 
   // Make named list for output
   SEXP lazy = PROTECT(allocVector(VECSXP, 2));
-  if (NAMED(promise) < 2)
-    SET_NAMED(promise, 2);
+  MARK_NOT_MUTABLE(promise);
   SET_VECTOR_ELT(lazy, 0, promise);
   SET_VECTOR_ELT(lazy, 1, env);
 
@@ -63,10 +62,13 @@ SEXP make_lazy_dots(SEXP env, SEXP follow_symbols_, SEXP ignore_empty_) {
   int follow_symbols = asLogical(follow_symbols_);
   int ignore_empty = asLogical(ignore_empty_);
 
+  // Hush rchk false positive
+  PROTECT(dots);
+
   if (dots == R_MissingArg) {
     SEXP out = PROTECT(Rf_allocVector(VECSXP, 0));
     setAttrib(out, install("class"), PROTECT(mkString("lazy_dots")));
-    UNPROTECT(2);
+    UNPROTECT(3);
     return out;
   }
 
@@ -101,7 +103,7 @@ SEXP make_lazy_dots(SEXP env, SEXP follow_symbols_, SEXP ignore_empty_) {
   setAttrib(lazy_dots, install("names"), names);
   setAttrib(lazy_dots, install("class"), PROTECT(mkString("lazy_dots")));
 
-  UNPROTECT(3);
+  UNPROTECT(4);
 
   return lazy_dots;
 }
diff --git a/src/name.c b/src/name.c
index 0056de8..cccde7d 100644
--- a/src/name.c
+++ b/src/name.c
@@ -30,6 +30,10 @@ SEXP lhs_name(SEXP x) {
   SEXP x2 = PROTECT(Rf_shallow_duplicate(x));
 
   SEXP names = Rf_getAttrib(x2, R_NamesSymbol);
+
+  // Hush rchk false positives
+  PROTECT(names);
+
   if (names == R_NilValue) {
     names = Rf_allocVector(STRSXP, n);
     Rf_setAttrib(x2, R_NamesSymbol, names);
@@ -40,16 +44,20 @@ SEXP lhs_name(SEXP x) {
     if (!is_formula(xi) || Rf_length(xi) != 3)
       continue;
 
+    // Hush rchk false positives
+    SEXP p_lhs = PROTECT(lhs(xi));
+    SEXP p_env = PROTECT(env(xi));
+
     // set name
-    SEXP name = PROTECT(Rf_eval(lhs(xi), env(xi)));
+    SEXP name = PROTECT(Rf_eval(p_lhs, p_env));
     if (TYPEOF(name) != NILSXP)
       SET_STRING_ELT(names, i, as_name(name));
-    UNPROTECT(1);
 
     // replace with RHS of formula
     SET_VECTOR_ELT(x2, i, make_formula1(CADDR(xi), env(xi)));
+    UNPROTECT(3);
   }
 
-  UNPROTECT(1);
+  UNPROTECT(2);
   return x2;
 }
diff --git a/src/utils.c b/src/utils.c
index 29a8e12..3995bfb 100644
--- a/src/utils.c
+++ b/src/utils.c
@@ -3,15 +3,19 @@
 #include <Rinternals.h>
 #include <stdbool.h>
 
+bool is_symbol_str(SEXP sym, const char* f) {
+  return !strcmp(CHAR(PRINTNAME(sym)), f);
+}
+
 bool is_call_to(SEXP x, const char* f) {
   if (!Rf_isLanguage(x))
     return false;
 
   SEXP fun = CAR(x);
-  if (!Rf_isSymbol(fun))
+  if (Rf_isSymbol(fun))
+    return is_symbol_str(fun, f);
+  else
     return false;
-
-  return fun == Rf_install(f);
 }
 
 bool is_lazy_load(SEXP x) {
diff --git a/tests/testthat/test-formula.R b/tests/testthat/test-formula.R
index e8f42a3..44d8808 100644
--- a/tests/testthat/test-formula.R
+++ b/tests/testthat/test-formula.R
@@ -2,9 +2,7 @@ context("formula")
 
 # Creation ----------------------------------------------------------------
 
-test_that("expr must be valid type", {
-  expect_error(f_new(list()), "must be a language object")
-  expect_error(f_new(quote(a), list()), "must be a language object")
+test_that("env must be an environment", {
   expect_error(f_new(quote(a), env = list()), "must be an environment")
 })
 
diff --git a/vignettes/lazyeval.nb.html b/vignettes/lazyeval.nb.html
deleted file mode 100644
index 64804e8..0000000
--- a/vignettes/lazyeval.nb.html
+++ /dev/null
@@ -1,335 +0,0 @@
-<!DOCTYPE html>
-
-<html xmlns="http://www.w3.org/1999/xhtml">
-
-<head>
-
-<meta charset="utf-8">
-<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
-<meta name="generator" content="pandoc" />
-
-
-<meta name="author" content="Hadley Wickham" />
-
-
-<title>Non-standard evaluation</title>
-
-<script src="data:application/x-javascript;base64,LyohIGpRdWVyeSB2MS4xMS4zIHwgKGMpIDIwMDUsIDIwMTUgalF1ZXJ5IEZvdW5kYXRpb24sIEluYy4gfCBqcXVlcnkub3JnL2xpY2Vuc2UgKi8KIWZ1bmN0aW9uKGEsYil7Im9iamVjdCI9PXR5cGVvZiBtb2R1bGUmJiJvYmplY3QiPT10eXBlb2YgbW9kdWxlLmV4cG9ydHM/bW9kdWxlLmV4cG9ydHM9YS5kb2N1bWVudD9iKGEsITApOmZ1bmN0aW9uKGEpe2lmKCFhLmRvY3VtZW50KXRocm93IG5ldyBFcnJvcigialF1ZXJ5IHJlcXVpcmVzIGEgd2luZG93IHdpdGggYSBkb2N1bWVudCIpO3JldHVybiBiKGEpfTpiKGEpfSgidW5kZWZpbmVkIiE9dHlwZW9mIHdpbmRvdz93aW5kb3c6dG [...]
-<meta name="viewport" content="width=device-width, initial-scale=1" />
-<link href="data:text/css;charset=utf-8,html%7Bfont%2Dfamily%3Asans%2Dserif%3B%2Dms%2Dtext%2Dsize%2Dadjust%3A100%25%3B%2Dwebkit%2Dtext%2Dsize%2Dadjust%3A100%25%7Dbody%7Bmargin%3A0%7Darticle%2Caside%2Cdetails%2Cfigcaption%2Cfigure%2Cfooter%2Cheader%2Chgroup%2Cmain%2Cmenu%2Cnav%2Csection%2Csummary%7Bdisplay%3Ablock%7Daudio%2Ccanvas%2Cprogress%2Cvideo%7Bdisplay%3Ainline%2Dblock%3Bvertical%2Dalign%3Abaseline%7Daudio%3Anot%28%5Bcontrols%5D%29%7Bdisplay%3Anone%3Bheight%3A0%7D%5Bhidden%5D%2Ctem [...]
-<script src="data:application/x-javascript;base64,LyohCiAqIEJvb3RzdHJhcCB2My4zLjUgKGh0dHA6Ly9nZXRib290c3RyYXAuY29tKQogKiBDb3B5cmlnaHQgMjAxMS0yMDE1IFR3aXR0ZXIsIEluYy4KICogTGljZW5zZWQgdW5kZXIgdGhlIE1JVCBsaWNlbnNlCiAqLwppZigidW5kZWZpbmVkIj09dHlwZW9mIGpRdWVyeSl0aHJvdyBuZXcgRXJyb3IoIkJvb3RzdHJhcCdzIEphdmFTY3JpcHQgcmVxdWlyZXMgalF1ZXJ5Iik7K2Z1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0Ijt2YXIgYj1hLmZuLmpxdWVyeS5zcGxpdCgiICIpWzBdLnNwbGl0KCIuIik7aWYoYlswXTwyJiZiWzFdPDl8fDE9PWJbMF0mJjk9PWJbMV0mJmJbMl08MSl0aHJvdy [...]
-<script src="data:application/x-javascript;base64,LyoqCiogQHByZXNlcnZlIEhUTUw1IFNoaXYgMy43LjIgfCBAYWZhcmthcyBAamRhbHRvbiBAam9uX25lYWwgQHJlbSB8IE1JVC9HUEwyIExpY2Vuc2VkCiovCi8vIE9ubHkgcnVuIHRoaXMgY29kZSBpbiBJRSA4CmlmICghIXdpbmRvdy5uYXZpZ2F0b3IudXNlckFnZW50Lm1hdGNoKCJNU0lFIDgiKSkgewohZnVuY3Rpb24oYSxiKXtmdW5jdGlvbiBjKGEsYil7dmFyIGM9YS5jcmVhdGVFbGVtZW50KCJwIiksZD1hLmdldEVsZW1lbnRzQnlUYWdOYW1lKCJoZWFkIilbMF18fGEuZG9jdW1lbnRFbGVtZW50O3JldHVybiBjLmlubmVySFRNTD0ieDxzdHlsZT4iK2IrIjwvc3R5bGU+IixkLm [...]
-<script src="data:application/x-javascript;base64,LyohIFJlc3BvbmQuanMgdjEuNC4yOiBtaW4vbWF4LXdpZHRoIG1lZGlhIHF1ZXJ5IHBvbHlmaWxsICogQ29weXJpZ2h0IDIwMTMgU2NvdHQgSmVobAogKiBMaWNlbnNlZCB1bmRlciBodHRwczovL2dpdGh1Yi5jb20vc2NvdHRqZWhsL1Jlc3BvbmQvYmxvYi9tYXN0ZXIvTElDRU5TRS1NSVQKICogICovCgovLyBPbmx5IHJ1biB0aGlzIGNvZGUgaW4gSUUgOAppZiAoISF3aW5kb3cubmF2aWdhdG9yLnVzZXJBZ2VudC5tYXRjaCgiTVNJRSA4IikpIHsKIWZ1bmN0aW9uKGEpeyJ1c2Ugc3RyaWN0IjthLm1hdGNoTWVkaWE9YS5tYXRjaE1lZGlhfHxmdW5jdGlvbihhKXt2YXIgYixjPWEuZG [...]
-
-<style type="text/css">code{white-space: pre;}</style>
-<link href="data:text/css;charset=utf-8,pre%20%2Eoperator%2C%0Apre%20%2Eparen%20%7B%0Acolor%3A%20rgb%28104%2C%20118%2C%20135%29%0A%7D%0Apre%20%2Eliteral%20%7B%0Acolor%3A%20rgb%2888%2C%2072%2C%20246%29%0A%7D%0Apre%20%2Enumber%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%20205%29%3B%0A%7D%0Apre%20%2Ecomment%20%7B%0Acolor%3A%20rgb%2876%2C%20136%2C%20107%29%3B%0A%7D%0Apre%20%2Ekeyword%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%20255%29%3B%0A%7D%0Apre%20%2Eidentifier%20%7B%0Acolor%3A%20rgb%280%2C%200%2C%20 [...]
-<script src="data:application/x-javascript;base64,CnZhciBobGpzPW5ldyBmdW5jdGlvbigpe2Z1bmN0aW9uIG0ocCl7cmV0dXJuIHAucmVwbGFjZSgvJi9nbSwiJmFtcDsiKS5yZXBsYWNlKC88L2dtLCImbHQ7Iil9ZnVuY3Rpb24gZihyLHEscCl7cmV0dXJuIFJlZ0V4cChxLCJtIisoci5jST8iaSI6IiIpKyhwPyJnIjoiIikpfWZ1bmN0aW9uIGIocil7Zm9yKHZhciBwPTA7cDxyLmNoaWxkTm9kZXMubGVuZ3RoO3ArKyl7dmFyIHE9ci5jaGlsZE5vZGVzW3BdO2lmKHEubm9kZU5hbWU9PSJDT0RFIil7cmV0dXJuIHF9aWYoIShxLm5vZGVUeXBlPT0zJiZxLm5vZGVWYWx1ZS5tYXRjaCgvXHMrLykpKXticmVha319fWZ1bmN0aW9uIGgodC [...]
-<style type="text/css">
-  pre:not([class]) {
-    background-color: white;
-  }
-</style>
-<script type="text/javascript">
-if (window.hljs && document.readyState && document.readyState === "complete") {
-   window.setTimeout(function() {
-      hljs.initHighlighting();
-   }, 0);
-}
-</script>
-
-
-
-<style type="text/css">
-h1 {
-  font-size: 34px;
-}
-h1.title {
-  font-size: 38px;
-}
-h2 {
-  font-size: 30px;
-}
-h3 {
-  font-size: 24px;
-}
-h4 {
-  font-size: 18px;
-}
-h5 {
-  font-size: 16px;
-}
-h6 {
-  font-size: 12px;
-}
-</style>
-
-
-</head>
-
-<body>
-
-<style type="text/css">
-.main-container {
-  max-width: 940px;
-  margin-left: auto;
-  margin-right: auto;
-}
-code {
-  color: inherit;
-  background-color: rgba(0, 0, 0, 0.04);
-}
-img {
-  max-width:100%;
-  height: auto;
-}
-.tabbed-pane {
-  padding-top: 12px;
-}
-button.code-folding-btn:focus {
-  outline: none;
-}
-</style>
-
-
-<div class="container-fluid main-container">
-
-<!-- tabsets -->
-<script src="data:application/x-javascript;base64,Cgp3aW5kb3cuYnVpbGRUYWJzZXRzID0gZnVuY3Rpb24odG9jSUQpIHsKCiAgLy8gYnVpbGQgYSB0YWJzZXQgZnJvbSBhIHNlY3Rpb24gZGl2IHdpdGggdGhlIC50YWJzZXQgY2xhc3MKICBmdW5jdGlvbiBidWlsZFRhYnNldCh0YWJzZXQpIHsKCiAgICAvLyBjaGVjayBmb3IgZmFkZSBhbmQgcGlsbHMgb3B0aW9ucwogICAgdmFyIGZhZGUgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1mYWRlIik7CiAgICB2YXIgcGlsbHMgPSB0YWJzZXQuaGFzQ2xhc3MoInRhYnNldC1waWxscyIpOwogICAgdmFyIG5hdkNsYXNzID0gcGlsbHMgPyAibmF2LXBpbGxzIiA6ICJuYXYtdGFicyI7CgogIC [...]
-<script>
-$(document).ready(function () {
-  window.buildTabsets("TOC");
-});
-</script>
-
-<!-- code folding -->
-<script src="data:application/x-javascript;base64,Cgp3aW5kb3cuaW5pdGlhbGl6ZUNvZGVGb2xkaW5nID0gZnVuY3Rpb24oc2hvdykgewoKICAvLyBoYW5kbGVycyBmb3Igc2hvdy1hbGwgYW5kIGhpZGUgYWxsCiAgJCgiI3JtZC1zaG93LWFsbC1jb2RlIikuY2xpY2soZnVuY3Rpb24oKSB7CiAgICAkKCdkaXYuci1jb2RlLWNvbGxhcHNlJykuZWFjaChmdW5jdGlvbigpIHsKICAgICAgJCh0aGlzKS5jb2xsYXBzZSgnc2hvdycpOwogICAgfSk7CiAgfSk7CiAgJCgiI3JtZC1oaWRlLWFsbC1jb2RlIikuY2xpY2soZnVuY3Rpb24oKSB7CiAgICAkKCdkaXYuci1jb2RlLWNvbGxhcHNlJykuZWFjaChmdW5jdGlvbigpIHsKICAgICAgJCh0aG [...]
-<script>
-$(document).ready(function () {
-  window.initializeCodeFolding("show" === "show");
-});
-</script>
-
-
-
-
-
-
-<div class="fluid-row" id="header">
-
-<div class="btn-group pull-right">
-<button type="button" class="btn btn-default btn-xs dropdown-toggle" data-toggle="dropdown" aria-haspopup="true" aria-expanded="false"><span>Code</span> <span class="caret"></span></button>
-<ul class="dropdown-menu" style="min-width: 50px;">
-<li><a id="rmd-show-all-code" href="#">Show All</a></li>
-<li><a id="rmd-hide-all-code" href="#">Hide All</a></li>
-</ul>
-</div>
-
-
-<h1 class="title toc-ignore">Non-standard evaluation</h1>
-<h4 class="author"><em>Hadley Wickham</em></h4>
-<h4 class="date"><em><code>r Sys.Date()</code></em></h4>
-
-</div>
-
-
-<p>This document describes lazyeval, a package that provides principled tools to perform non-standard evaluation (NSE) in R. You should read this vignette if you want to program with packages like dplyr and ggplot2<a href="#fn1" class="footnoteRef" id="fnref1"><sup>1</sup></a>, or you want a principled way of working with delayed expressions in your own package. As the name suggests, non-standard evaluation breaks away from the standard evaluation (SE) rules in order to do something spec [...]
-<ol style="list-style-type: decimal">
-<li><p><strong>Labelling</strong> enhances plots and tables by using the expressions supplied to a function, rather than their values. For example, note the axis labels in this plot:</p></li>
-<li><p><strong>Non-standard scoping</strong> looks for objects in places other than the current environment. For example, base R has <code>with()</code>, <code>subset()</code>, and <code>transform()</code> that look for objects in a data frame (or list) before the current environment:</p></li>
-<li><p><strong>Metaprogramming</strong> is a catch-all term that covers all other uses of NSE (such as in <code>bquote()</code> and <code>library()</code>). Metaprogramming is so called because it involves computing on the unevaluated code in some way.</p></li>
-</ol>
-<p>This document is broadly organised according to the three types of non-standard evaluation described above. The main difference is that after <a href="#labelling">labelling</a>, we’ll take a detour to learn more about <a href="#formulas">formulas</a>. You’re probably familiar with formulas from linear models (e.g. <code>lm(mpg ~ displ, data = mtcars)</code>) but formulas are more than just a tool for modelling: they are a general way of capturing an unevaluated expression.</p>
-<p>The approaches recommended here are quite different to my previous generation of recommendations. I am fairly confident these new approaches are correct, and will not have to change substantially again. The current tools make it easy to solve a number of practical problems that were previously challenging and are rooted in <a href="http://repository.readscheme.org/ftp/papers/pepm99/bawden.pdf">long-standing theory</a>.</p>
-<div id="labelling" class="section level2">
-<h2>Labelling</h2>
-<p>In base R, the classic way to turn an argument into a label is to use <code>deparse(substitute(x))</code>:</p>
-<p>There are two potential problems with this approach:</p>
-<ol style="list-style-type: decimal">
-<li><p>For long some expressions, <code>deparse()</code> generates a character vector with length > 1:</p></li>
-<li><p><code>substitute()</code> only looks one level up, so you lose the original label if the function isn’t called directly:</p></li>
-</ol>
-<p>Both of these problems are resolved by <code>lazyeval::expr_text()</code>:</p>
-<p>There are two variations on the theme of <code>expr_text()</code>:</p>
-<ul>
-<li><p><code>expr_find()</code> find the underlying expression. It works similarly to <code>substitute()</code> but will follow a chain of promises back up to the original expression. This is often useful for <a href="#metaprogramming">metaprogramming</a>.</p></li>
-<li><p><code>expr_label()</code> is a customised version of <code>expr_text()</code> that produces labels designed to be used in messages to the user:</p></li>
-</ul>
-<div id="exercises" class="section level3">
-<h3>Exercises</h3>
-<ol style="list-style-type: decimal">
-<li><p><code>plot()</code> uses <code>deparse(substitute(x))</code> to generate labels for the x and y axes. Can you generate input that causes it to display bad labels? Write your own wrapper around <code>plot()</code> that uses <code>expr_label()</code> to compute <code>xlim</code> and <code>ylim</code>.</p></li>
-<li><p>Create a simple implementation of <code>mean()</code> that stops with an informative error message if the argument is not numeric:</p></li>
-<li><p>Read the source code for <code>expr_text()</code>. How does it work? What additional arguments to <code>deparse()</code> does it use?</p></li>
-</ol>
-</div>
-</div>
-<div id="formulas" class="section level2">
-<h2>Formulas</h2>
-<p>Non-standard scoping is probably the most useful NSE tool, but before we can talk about a solid approach, we need to take a detour to talk about formulas. Formulas are a familiar tool from linear models, but their utility is not limited to models. In fact, formulas are a powerful, general purpose tool, because a formula captures two things:</p>
-<ol style="list-style-type: decimal">
-<li>An unevaluated expression.</li>
-<li>The context (environment) in which the expression was created.</li>
-</ol>
-<p><code>~</code> is a single character that allows you to say: “I want to capture the meaning of this code, without evaluating it right away”. For that reason, the formula can be thought of as a “quoting” operator.</p>
-<div id="definition-of-a-formula" class="section level3">
-<h3>Definition of a formula</h3>
-<p>Technically, a formula is a “language” object (i.e. an unevaluated expression) with a class of “formula” and an attribute that stores the environment:</p>
-<p>The structure of the underlying object is slightly different depending on whether you have a one-sided or two-sided formula:</p>
-<ul>
-<li><p>One-sided formulas have length two:</p></li>
-<li><p>Two-sided formulas have length three:</p></li>
-</ul>
-<p>To abstract away these differences, lazyeval provides <code>f_rhs()</code> and <code>f_lhs()</code> to access either side of the formula, and <code>f_env()</code> to access its environment:</p>
-</div>
-<div id="evaluating-a-formula" class="section level3">
-<h3>Evaluating a formula</h3>
-<p>A formula captures delays the evaluation of an expression so you can later evaluate it with <code>f_eval()</code>:</p>
-<p>This allows you to use a formula as a robust way of delaying evaluation, cleanly separating the creation of the formula from its evaluation. Because formulas capture the code and context, you get the correct result even when a formula is created and evaluated in different places. In the following example, note that the value of <code>x</code> inside <code>add_1000()</code> is used:</p>
-<p>It can be hard to see what’s going on when looking at a formula because important values are stored in the environment, which is largely opaque. You can use <code>f_unwrap()</code> to replace names with their corresponding values:</p>
-</div>
-<div id="non-standard-scoping" class="section level3">
-<h3>Non-standard scoping</h3>
-<p><code>f_eval()</code> has an optional second argument: a named list (or data frame) that overrides values found in the formula’s environment.</p>
-<p>This makes it very easy to implement non-standard scoping:</p>
-<p>One challenge with non-standard scoping is that we’ve introduced some ambiguity. For example, in the code below does <code>x</code> come from <code>mydata</code> or the environment?</p>
-<p>You can’t tell without knowing whether or not <code>mydata</code> has a variable called <code>x</code>. To overcome this problem, <code>f_eval()</code> provides two pronouns:</p>
-<ul>
-<li><code>.data</code> is bound to the data frame.</li>
-<li><code>.env</code> is bound to the formula environment.</li>
-</ul>
-<p>They both start with <code>.</code> to minimise the chances of clashing with existing variables.</p>
-<p>With these pronouns we can rewrite the previous formula to remove the ambiguity:</p>
-<p>If the variable or object doesn’t exist, you’ll get an informative error:</p>
-</div>
-<div id="unquoting" class="section level3">
-<h3>Unquoting</h3>
-<p><code>f_eval()</code> has one more useful trick up its sleeve: unquoting. Unquoting allows you to write functions where the user supplies part of the formula. For example, the following function allows you to compute the mean of any column (or any function of a column):</p>
-<p>To see how this works, we can use <code>f_interp()</code> which <code>f_eval()</code> calls internally (you shouldn’t call it in your own code, but it’s useful for debugging). The key is <code>uq()</code>: <code>uq()</code> evaluates its first (and only) argument and inserts the value into the formula:</p>
-<p>Unquoting allows you to create code “templates”, where you write most of the expression, while still allowing the user to control important components. You can even use <code>uq()</code> to change the function being called:</p>
-<p>Note that <code>uq()</code> only takes the RHS of a formula, which makes it difficult to insert literal formulas into a call:</p>
-<p>You can instead use <code>uqf()</code> which uses the whole formula, not just the RHS:</p>
-<p>Unquoting is powerful, but it only allows you to modify a single argument: it doesn’t allow you to add an arbitrary number of arguments. To do that, you’ll need “unquote-splice”, or <code>uqs()</code>. The first (and only) argument to <code>uqs()</code> should be a list of arguments to be spliced into the call:</p>
-</div>
-<div id="exercises-1" class="section level3">
-<h3>Exercises</h3>
-<ol style="list-style-type: decimal">
-<li><p>Create a wrapper around <code>lm()</code> that allows the user to supply the response and predictors as two separate formulas.</p></li>
-<li><p>Compare and contrast <code>f_eval()</code> with <code>with()</code>.</p></li>
-<li><p>Why does this code work even though <code>f</code> is defined in two places? (And one of them is not a function).</p></li>
-</ol>
-</div>
-</div>
-<div id="non-standard-scoping-1" class="section level2">
-<h2>Non-standard scoping</h2>
-<p>Non-standard scoping (NSS) is an important part of R because it makes it easy to write functions tailored for interactive data exploration. These functions require less typing, at the cost of some ambiguity and “magic”. This is a good trade-off for interactive data exploration because you want to get ideas out of your head and into the computer as quickly as possible. If a function does make a bad guess, you’ll spot it quickly because you’re working interactively.</p>
-<p>There are three challenges to implementing non-standard scoping:</p>
-<ol style="list-style-type: decimal">
-<li><p>You must correctly delay the evaluation of a function argument, capturing both the computation (the expression), and the context (the environment). I recommend making this explicit by requiring the user to “quote” any NSS arguments with <code>~</code>, and then evaluating explicit with <code>f_eval()</code>.</p></li>
-<li><p>When writing functions that use NSS-functions, you need some way to avoid the automatic lookup and be explicit about where objects should be found. <code>f_eval()</code> solves this problem with the <code>.data.</code> and <code>.env</code> pronouns.</p></li>
-<li><p>You need some way to allow the user to supply parts of a formula. <code>f_eval()</code> solves this with unquoting.</p></li>
-</ol>
-<p>To illustrate these challenges, I will implement a <code>sieve()</code> function that works similarly to <code>base::subset()</code> or <code>dplyr::filter()</code>. The goal of <code>sieve()</code> is to make it easy to select observations that match criteria defined by a logical expression. <code>sieve()</code> has three advantages over <code>[</code>:</p>
-<ol style="list-style-type: decimal">
-<li><p>It is much more compact when the condition uses many variables, because you don’t need to repeat the name of the data frame many times.</p></li>
-<li><p>It drops rows where the condition evaluates to <code>NA</code>, rather than filling them with <code>NA</code>s.</p></li>
-<li><p>It always returns a data frame.</p></li>
-</ol>
-<p>The implementation of <code>sieve()</code> is straightforward. First we use <code>f_eval()</code> to perform NSS. Then we then check that we have a logical vector, replace <code>NA</code>s with <code>FALSE</code>, and subset with <code>[</code>.</p>
-<div id="programming-with-sieve" class="section level3">
-<h3>Programming with <code>sieve()</code></h3>
-<p>Imagine that you’ve written some code that looks like this:</p>
-<p>(This is a contrived example, but it illustrates all of the important issues you’ll need to consider when writing more useful functions.)</p>
-<p>Instead of continuing to copy-and-paste your code, you decide to wrap up the common behaviour in a function:</p>
-<p>There are two ways that this function might fail:</p>
-<ol style="list-style-type: decimal">
-<li><p>The data frame might not have a variable called <code>x</code>. This will fail unless there’s a variable called <code>x</code> hanging around in the global environment:</p></li>
-<li><p>The data frame might have a variable called <code>threshold</code>:</p></li>
-</ol>
-<p>These failures are partiuclarly pernicious because instead of throwing an error they silently produce the wrong answer. Both failures arise because <code>f_eval()</code> introduces ambiguity by looking in two places for each name: the supplied data and formula environment.</p>
-<p>To make <code>threshold_x()</code> more reliable, we need to be more explicit by using the <code>.data</code> and <code>.env</code> pronouns:</p>
-<p>Here <code>.env</code> is bound to the environment where <code>~</code> is evaluated, namely the inside of <code>threshold_x()</code>.</p>
-</div>
-<div id="adding-arguments" class="section level3">
-<h3>Adding arguments</h3>
-<p>The <code>threshold_x()</code> function is not very useful because it’s bound to a specific variable. It would be more powerful if we could vary both the threshold and the variable it applies to. We can do that by taking an additional argument to specify which variable to use.</p>
-<p>One simple approach is to use a string and <code>[[</code>:</p>
-<p>This is a simple and robust solution, but only allows us to use an existing variable, not an arbitrary expression like <code>sqrt(x)</code>.</p>
-<p>A more general solution is to allow the user to supply a formula, and use unquoting:</p>
-<p>In this case, it’s the responsibility of the user to ensure the <code>variable</code> is specified unambiguously. <code>f_eval()</code> is designed so that <code>.data</code> and <code>.env</code> work even when evaluated inside of <code>uq()</code>:</p>
-</div>
-<div id="dot-dot-dot" class="section level3">
-<h3>Dot-dot-dot</h3>
-<p>There is one more tool that you might find useful for functions that take <code>...</code>. For example, the code below implements a function similar to <code>dplyr::mutate()</code> or <code>base::transform()</code>.</p>
-<p>(NB: the first argument is a non-syntactic name (i.e. it requires quoting with <code>`</code>) so it doesn’t accidentally match one of the names of the new variables.)</p>
-<p><code>transmogrifty()</code> makes it easy to add new variables to a data frame:</p>
-<p>One problem with this implementation is that it’s hard to specify the names of the generated variables. Imagine you want a function where the name and expression are in separate variables. This is awkward because the variable name is supplied as an argument name to <code>mogrify()</code>:</p>
-<p>Lazyeval provides the <code>f_list()</code> function to make writing this sort of function a little easier. It takes a list of formulas and evaluates the LHS of each formula (if present) to rename the elements:</p>
-<p>If we tweak <code>mogrify()</code> to use <code>f_list()</code> instead of <code>list()</code>:</p>
-<p><code>add_new()</code> becomes much simpler:</p>
-</div>
-<div id="exercises-2" class="section level3">
-<h3>Exercises</h3>
-<ol style="list-style-type: decimal">
-<li><p>Write a function that selects all rows of <code>df</code> where <code>variable</code> is greater than its mean. Make the function more general by allowing the user to specify a function to use instead of <code>mean()</code> (e.g. <code>median()</code>).</p></li>
-<li><p>Create a version of <code>mogrify()</code> where the first argument is <code>x</code>? What happens if you try to create a new variable called <code>x</code>?</p></li>
-</ol>
-</div>
-</div>
-<div id="non-standard-evaluation" class="section level2">
-<h2>Non-standard evaluation</h2>
-<p>In some situations you might want to eliminate the formula altogether, and allow the user to type expressions directly. I was once much enamoured with this approach (witness ggplot2, dplyr, …). However, I now think that it should be used sparingly because explict quoting with <code>~</code> leads to simpler code, and makes it more clear to the user that something special is going on.</p>
-<p>That said, lazyeval does allow you to eliminate the <code>~</code> if you really want to. In this case, I recommend having both a NSE and SE version of the function. The SE version, which takes formuals, should have suffix <code>_</code>:</p>
-<p>Then create the NSE version which doesn’t need the explicit formula. The key is the use of <code>f_capture()</code> which takes an unevaluated argument (a promise) and captures it as a formula:</p>
-<p>If you’re familiar with <code>substitute()</code> you might expect the same drawbacks to apply. However, <code>f_capture()</code> is smart enough to follow a chain of promises back to the original value, so, for example, this code works fine:</p>
-<div id="dot-dot-dot-1" class="section level3">
-<h3>Dot-dot-dot</h3>
-<p>If you want a <code>...</code> function that doesn’t require formulas, I recommend that the SE version take a list of arguments, and the NSE version uses <code>dots_capture()</code> to capture multiple arguments as a list of formulas.</p>
-</div>
-<div id="exercises-3" class="section level3">
-<h3>Exercises</h3>
-<ol style="list-style-type: decimal">
-<li>Recreate <code>subscramble()</code> using <code>base::subset()</code> instead of <code>sieve()</code>. Why does it fail?</li>
-</ol>
-</div>
-</div>
-<div id="metaprogramming" class="section level2">
-<h2>Metaprogramming</h2>
-<p>The final use of non-standard evaluation is to do metaprogramming. This is a catch-all term that encompasses any function that does computation on an unevaluated expression. You can learn about metaprogrgramming in <a href="http://adv-r.had.co.nz/Expressions.html" class="uri">http://adv-r.had.co.nz/Expressions.html</a>, particularly <a href="http://adv-r.had.co.nz/Expressions.html#ast-funs" class="uri">http://adv-r.had.co.nz/Expressions.html#ast-funs</a>. Over time, the goal is to mov [...]
-</div>
-<div class="footnotes">
-<hr />
-<ol>
-<li id="fn1"><p>Currently neither ggplot2 nor dplyr actually use these tools since I’ve only just figured it out. But I’ll be working hard to make sure all my packages are consistent in the near future.<a href="#fnref1">↩</a></p></li>
-</ol>
-</div>
-
-
-
-
-</div>
-
-<script>
-
-// add bootstrap table styles to pandoc tables
-$(document).ready(function () {
-  $('tr.header').parent('thead').parent('table').addClass('table table-condensed');
-});
-
-</script>
-
-<!-- dynamically load mathjax for compatibility with self-contained -->
-<script>
-  (function () {
-    var script = document.createElement("script");
-    script.type = "text/javascript";
-    script.src  = "https://cdn.mathjax.org/mathjax/latest/MathJax.js?config=TeX-AMS-MML_HTMLorMML";
-    document.getElementsByTagName("head")[0].appendChild(script);
-  })();
-</script>
-
-</body>
-<!-- rnb-cache-data-begin
-    chunks.json:eyJjaHVua19kZWZpbml0aW9ucyI6W10sImRvY193cml0ZV90aW1lIjoxNDYxMTY0NzI2fQ==
-rnb-cache-data-end -->
-<!-- rnb-document-source LS0tCnRpdGxlOiAiTm9uLXN0YW5kYXJkIGV2YWx1YXRpb24iCmF1dGhvcjogIkhhZGxleSBXaWNraGFtIgpkYXRlOiAiYHIgU3lzLkRhdGUoKWAiCm91dHB1dDogcm1hcmtkb3duOjpodG1sX3ZpZ25ldHRlCnZpZ25ldHRlOiA+CiAgJVxWaWduZXR0ZUluZGV4RW50cnl7Tm9uLXN0YW5kYXJkIGV2YWx1YXRpb259CiAgJVxWaWduZXR0ZUVuZ2luZXtrbml0cjo6cm1hcmtkb3dufQogICVcVmlnbmV0dGVFbmNvZGluZ3tVVEYtOH0KLS0tCgpgYGB7ciwgaW5jbHVkZSA9IEZBTFNFfQpsaWJyYXJ5KGxhenlldmFsKQprbml0cjo6b3B0c19jaHVuayRzZXQoY29sbGFwc2UgPSBUUlVFLCBjb21tZW50ID0gIiM+IikKYGBgCgp [...]
-</html>

-- 
Alioth's /usr/local/bin/git-commit-notice on /srv/git.debian.org/git/debian-med/r-cran-lazyeval.git



More information about the debian-med-commit mailing list