R utiliza el alcance léxico, lo que significa que si se hace referencia a un objeto pero no se define en una función, se busca en el entorno en el que se define la función , no en el entorno desde el que se llamó.
Se hace referencia a z en g pero no se define en g, por lo que mira al entorno en el que se define g y ese es el entorno dentro de f, entonces g usa z = 4.
En realidad, en este caso, el entorno en el que se define g es el mismo que el entorno desde el que se llama g, por lo que debe usarse z = 4 de cualquier forma que lo mire. Si las funciones predeterminadas al entorno global para buscar objetos no definidos en la función, entonces usaría z = 10, pero no es así como funciona R.
Hacer que funcione de manera diferente
Si por alguna razón quisiera forzar a g a buscar z en el entorno en el que se llama f, entonces podría hacerlo (donde se parent.frame()
refiere al entorno desde el que se llama f).
f2 <- function(x, envir = parent.frame()) {
g <- function(y) {
y + with(envir, z)
}
z <- 4
x + g(x)
}
z <- 10
f2(3)
## [1] 16
o podríamos usar y + envir$z
excepto que eso solo se vería en el marco primario y no en sus antepasados, mientras que with
se vería en ancestros del marco primario si no se encuentra en el marco primario.
Una alternativa es cambiar el entorno de g de esta manera para que busque envir
objetos que no se encuentran en g:
f3 <- function(x, envir = parent.frame()) {
g <- function(y) {
y + z
}
environment(g) <- envir
z <- 4
x + g(x)
}
z <- 10
f3(3)
## [1] 16