hadley / adv-r

Advanced R: a book
http://adv-r.hadley.nz
Other
2.36k stars 1.71k forks source link

confused example about `subset_base()` can't work with `lapply()` in "20.6 Base evaluation" #1417

Closed dongzhuoer closed 5 years ago

dongzhuoer commented 5 years ago
library(rlang)

subset_base <- function(data, rows) {
  rows <- substitute(rows)
  rows_val <- eval(rows, data, caller_env())
  stopifnot(is.logical(rows_val))

  data[rows_val, , drop = FALSE]
}
local({
  y <- 2
  dfs <- list(data.frame(x = 1:3), data.frame(x = 4:6))
  lapply(dfs, subset_base, x == y)
})
Error in eval(rows, data, caller_env()) : object 'y' not found

But the book gives image

since you define y <- 20 in "20.2.3 Gotcha: function()"

dongzhuoer commented 5 years ago

By the way, I spend a while to understand why. You may need to add more explanation.

library(rlang)

subset_base2 <- function(data, rows) {
  env_print(caller_env())

  rows <- substitute(rows)
  rows_val <- eval(rows, data, caller_env())
  stopifnot(is.logical(rows_val))

  data[rows_val, , drop = FALSE]
}
local({
  y <- 2
  dfs <- list(data.frame(x = 1:3), data.frame(x = 4:6))
  lapply(dfs, subset_base2, x == y)
})
<environment: 0x6709e20>
parent: <environment: namespace:base>
bindings:
 * i: <int>
 * X: <list>
 * FUN: <fn>
 * ...: <...>
Error in eval(rows, data, caller_env()) : object 'y' not found

Then it's quite clear that subset_base2() is evaluated in lapply()'s execution environment. R finds variable by lexical scoping, y can't be found since it defined in where lapply() is callled, not there lapply() is defined (base package).

hadley commented 5 years ago

Thanks for pointing this out!

Here, I'm mostly interested in pointing out that this is a drawback, rather than explaining the exact cause (which you have correctly determined 😄)