El x
que está dentro de la función anónima es no la x
en el entorno global (su espacio de trabajo). Es una copia de x
, local para la función anónima. No es tan simple decir que R copia objetos en llamadas a funciones; R se esforzará por no copiar si puede, aunque una vez que modifique algo R tendrá que copiar el objeto.
Como @DWin señala, esta versión copiada de x
que ha sido modificado es devuelto por la llamada sapply()
, la salida solicitada no es lo que me sale:
> x <- c(1:10)
> print(x)
[1] 1 2 3 4 5 6 7 8 9 10
> sapply(1:10,function(i){
+ x[i] = 4
+ })
[1] 4 4 4 4 4 4 4 4 4 4
> print(x)
[1] 1 2 3 4 5 6 7 8 9 10
Claramente, el código no hizo casi lo que pensaste que sería El problema es que la salida de sapply()
no se asignó a un objeto y, por lo tanto, se imprime y luego se descarta.
La razón por la que su código incluso funciona se debe a las reglas de alcance de R. Realmente debería pasar a una función como argumentos de cualquier objeto que la función necesite. Sin embargo, si R no puede encontrar un objeto local para la función, buscará en el entorno primario un objeto que coincida con el nombre, y luego el elemento primario de ese entorno, si corresponde, hasta llegar al entorno global, el espacio de trabajo. Por lo tanto, su código funciona porque finalmente encontró un x
para trabajar, pero se copió inmediatamente, esa copia volvió al final de la llamada sapply()
.
Esta copia toma tiempo y memoria en muchos casos. Esta es una de las razones por las cuales las personas piensan que los bucles for
son lentos en R; no asignan almacenamiento a un objeto antes de llenarlo con un bucle. Si no asigna almacenamiento, R tiene que modificar/copiar el objeto para agregar el siguiente resultado del ciclo.
Otra vez sin embargo, no siempre es así de simple, en todas partes en R, por ejemplo, con los ambientes, en los que una copia de un entorno realmente sólo se refiere a la versión original:
> a <- new.env()
> a
<environment: 0x1af2ee0>
> b <- 4
> assign("b", b, env = a)
> a$b
[1] 4
> c <- a ## copy the environment to `c`
> assign("b", 7, env = c) ## assign something to `b` in env `c`
> c$b ## as expected
[1] 7
> a$b ## also changed `b` in `a` as `a` and `c` are actually the same thing
[1] 7
Si usted entiende este tipo de cosas, leyendo el manual R Language Definition que cubre muchos de los detalles de lo que sucede debajo del capó en R.
Gracias! Pero ¿por qué no uno escribe ese código en R? ¿Hay algún riesgo potencial o solo una convención? Creo que es bastante normal modificar objetos globales en una función en otros idiomas. –
En las funciones de idiomas funcionales no pueden tener efectos secundarios. R no es tan estricto, pero sigue siendo cierto que las funciones R limitan los efectos secundarios. Es mejor trabajar de la manera que se pretendía que fuera en lugar de tratar de escribir como si estuvieras escribiendo en otro idioma. Hay varios sistemas de objetos (S3, S4, Clases de referencia). S3 es el más utilizado. S4 es mucho más complejo. Las clases de referencia son una adición reciente. Es posible que desee explorar las clases de referencia, en particular. También hay algunos paquetes aportados por los usuarios que ofrecen diferentes paradigmas: proto y R.oo (y posiblemente otros). –
@Spirit Plus puede usar 'parent.frame (3)' en lugar de '.GlobalEnv' para almacenar x en un cierre en el que se ejecuta sapply, lo que sería mucho más seguro. (¿Por qué marco de función 3? 1-anónimo, marco de 2 sapply, recinto de 3 sapply) – mbq