organizaciones - ¿Por qué la evaluación de una expresión en system.time() hace que las variables estén disponibles en el entorno global?
entorno global de la administracion (3)
Creo que el expr
se evalúa antes de manejar eso a la función. Ejemplo POC:
> st <- function(expr){
+ eval(parse(text=expr))
+ }
>
> st(''aa <- 1'')
> aa
Error: object ''aa'' not found
Así que creo que la función obtiene expr
como solo aa
. Otro ejemplo:
> st <- function(expr){
+ str(expr)
+ }
>
> st(aa <- 1)
num 1
Podría estar equivocado, es más bien una intuición :) Pero gracias, ¡es un buen acertijo!
Actualizar:
> system.time(a <- 1)
user system elapsed
0 0 0
> a
[1] 1
> rm(a)
> fn <- function() a <- 1
> system.time(fn())
user system elapsed
0 0 0
> a
Error: object ''a'' not found
¿Alguien puede explicar qué sucede cuando se evalúa una expresión en system.time
? En particular, ¿por qué las variables declaradas en el argumento expr
visibles en el entorno global?
Aquí hay una versión system.time
de las entrañas del sistema. system.time
que no hace más que evaluar la expresión que se pasa a la función:
st <- function(expr){
expr
}
st(aa <- 1)
aa
[1] 1
Claramente, el efecto de esto es que crea la variable aa
en el entorno global. Esto me desconcierta, ya que pensé que asignar una variable dentro de una función la hace local en su alcance.
¿Qué pasa aquí?
Se debe a que los argumentos suministrados se evalúan en el marco de evaluación de la función de llamada (como se describe en la Sección 4.3.3 del documento Definición de lenguaje R).
La expresión envuelta por el usuario en system.time()
es un argumento proporcionado que se correlaciona posicionalmente con expr
. Luego, cuando la evaluación de expr
está forzada en el cuerpo de system.time
, se evalúa en el marco de evaluación de la función de llamada. Si se llamó a system.time()
desde .GlobalEnv
, es allí donde se llevarán a cabo las asignaciones que forman parte de expr
.
EDITAR:
Aquí hay un ejemplo que muestra que expr
se evalúa en el entorno global si es un argumento suministrado (pero no un predeterminado ).
st2 <- function(expr = newVar <- 33){
expr
}
# Using the default argument -- eval and assignment
# within evaluation frame of the function.
st2()
newVar
Error: object ''newVar'' not found
# Using a supplied argument -- eval and assignment
# within the calling function''s evaluation frame (here .GlobalEnv)
st2(newVar <- 44)
newVar
# [1] 44
EDITAR: según el comentario de @Tommy: la evaluación en realidad solo tiene lugar una vez que se usa el argumento expr (esa es la evaluación perezosa).
Lo que se pasa es un objeto de lenguaje, no una expresión. Básicamente anida la función <-
(con dos argumentos) dentro de la llamada a la función st (), y el resultado de la llamada <-
pasa a st. Como puede ver en ?assignOps
, la función <-
devuelve el valor asignado en silencio. Como @Josh ya te dijo, esta evaluación de la función anidada tiene lugar en el entorno desde el que se llama a la función.
Lo que haces, es equivalente a
st(mean(1:10))
Para ver la diferencia, puedes hacer:
st <- function(expr){
typeof(expr)
}
> st(aa <- 1)
[1] "double"
> st(expression(aa <- 1))
[1] "expression"
Para la estructura de la llamada, puede hacer:
st <- function(expr){
str(as.list(match.call()))
}
> st(mean(1:10))
List of 2
$ : symbol st
$ expr: language mean(1:10)
> st(aa <- 1)
List of 2
$ : symbol st
$ expr: language aa <- 1