uso - ¿Cómo se usa "<<-"(asignación del alcance) en R?
cuándo se utilizan las comillas (6)
Ayuda a pensar en <<-
como equivalente a assign
(si establece el parámetro inherits
en esa función en TRUE
). La ventaja de assign
es que le permite especificar más parámetros (por ejemplo, el entorno), por lo que prefiero usar assign
más de <<-
en la mayoría de los casos.
El uso de <<-
y assign(x, value, inherits=TRUE)
significa que "los entornos envolventes del entorno suministrado se buscan hasta que se encuentre la variable ''x''". En otras palabras, continuará recorriendo los entornos en orden hasta que encuentre una variable con ese nombre, y se lo asignará a eso. Esto puede estar dentro del alcance de una función o en el entorno global.
Para comprender lo que hacen estas funciones, también debe comprender los entornos R (por ejemplo, mediante la search
).
Regularmente uso estas funciones cuando estoy ejecutando una simulación grande y quiero guardar resultados intermedios. Esto le permite crear el objeto fuera del alcance de la función dada o apply
bucle. Eso es muy útil, especialmente si le preocupa que un bucle grande termine de forma inesperada (por ejemplo, una desconexión de la base de datos), en cuyo caso podría perder todo en el proceso. Esto sería equivalente a escribir sus resultados en una base de datos o archivo durante un proceso de ejecución larga, excepto que en su lugar se almacenan los resultados dentro del entorno R.
Mi advertencia principal con esto: tenga cuidado porque ahora está trabajando con variables globales, especialmente cuando usa <<-
. Esto significa que puede terminar en situaciones en las que una función utiliza un valor de objeto del entorno, cuando esperaba que utilizara uno que se suministró como parámetro. Esta es una de las cosas principales que la programación funcional intenta evitar (ver los efectos secundarios ). Evito este problema asignando mis valores a nombres de variables únicos (usando pegar con un conjunto o parámetros únicos) que nunca se usan en la función, pero que acabo de usar para el almacenamiento en caché y en caso de que necesite recuperarlos más tarde (o hacer algún meta -análisis sobre los resultados intermedios).
Acabo de leer sobre el alcance en la introducción de la R , y tengo mucha curiosidad sobre la <<-
tarea.
El manual mostró un (muy interesante) ejemplo para <<-
, que creo que entendí. Lo que todavía me falta es el contexto de cuándo puede ser útil.
Entonces, lo que me gustaría leer de ti son ejemplos (o enlaces a ejemplos) sobre cuándo el uso de <<-
puede ser interesante / útil. ¿Cuáles podrían ser los peligros de usarlo (parece fácil perder la pista de ellos) y cualquier consejo que pueda compartir?
El operador <<-
también puede ser útil para Clases de Referencia cuando se escriben Métodos de Referencia . Por ejemplo:
myRFclass <- setRefClass(Class = "RF",
fields = list(A = "numeric",
B = "numeric",
C = function() A + B))
myRFclass$methods(show = function() cat("A =", A, "B =", B, "C =",C))
myRFclass$methods(changeA = function() A <<- A*B) # note the <<-
obj1 <- myRFclass(A = 2, B = 3)
obj1
# A = 2 B = 3 C = 5
obj1$changeA()
obj1
# A = 6 B = 3 C = 9
Sobre este tema me gustaría señalar que el operador << se comportará de manera extraña cuando se aplica (incorrectamente) dentro de un ciclo for (también puede haber otros casos). Dado el siguiente código:
fortest <- function() {
mySum <- 0
for (i in c(1, 2, 3)) {
mySum <<- mySum + i
}
mySum
}
puede esperar que la función devuelva la suma esperada, 6, pero en su lugar devuelve 0, con una variable global mySum
está creando y se le asigna el valor 3. No puedo explicar completamente lo que está sucediendo aquí, pero ciertamente el cuerpo de un for loop no es un nuevo ''nivel'' de alcance. En cambio, parece que R se ve fuera de la función fortest
, no puede encontrar una variable mySum
a la que asignar, por lo que crea una y asigna el valor 1, la primera vez a través del ciclo. En iteraciones posteriores, el RHS en la asignación debe referirse a la variable mySum
interna (sin modificar), mientras que el LHS se refiere a la variable global. Por lo tanto, cada iteración sobrescribe el valor de la variable global al valor i
de esa iteración, por lo tanto, tiene el valor 3 al salir de la función.
Espero que esto ayude a alguien. ¡Esto me ha dejado perplejo durante un par de horas hoy! (Por cierto, simplemente reemplace << con <y la función funciona como se esperaba).
Un lugar donde utilicé <<-
estaba en GUI simples usando tcl / tk. Algunos de los ejemplos iniciales lo tienen, ya que necesita hacer una distinción entre las variables locales y globales para Statefullness. Ver por ejemplo
library(tcltk)
demo(tkdensity)
que usa <<-
. De lo contrario, estoy de acuerdo con Marek :) - una búsqueda en Google puede ayudar.
<<-
es más útil junto con cierres para mantener el estado. Aquí hay una sección de un documento mío reciente:
Un cierre es una función escrita por otra función. Los cierres se llaman así porque encierran el entorno de la función principal y pueden acceder a todas las variables y parámetros en esa función. Esto es útil porque nos permite tener dos niveles de parámetros. Un nivel de parámetros (el padre) controla cómo funciona la función. El otro nivel (el niño) hace el trabajo. El siguiente ejemplo muestra cómo se puede usar esta idea para generar una familia de funciones de potencia. La función principal ( power
) crea funciones hijo ( square
y cube
) que realmente hacen el trabajo duro.
power <- function(exponent) {
function(x) x ^ exponent
}
square <- power(2)
square(2) # -> [1] 4
square(4) # -> [1] 16
cube <- power(3)
cube(2) # -> [1] 8
cube(4) # -> [1] 64
La capacidad de administrar variables en dos niveles también permite mantener el estado a través de invocaciones de funciones al permitir que una función modifique variables en el entorno de su elemento principal. La clave para gestionar variables en diferentes niveles es el operador de asignación de doble flecha <<-
. A diferencia de la asignación habitual de flecha única ( <-
) que siempre funciona en el nivel actual, el operador de flecha doble puede modificar las variables en los niveles superiores.
Esto permite mantener un contador que registra cuántas veces se ha llamado una función, como se muestra en el siguiente ejemplo. Cada vez que se ejecuta new_counter
, crea un entorno, inicializa el contador i
en este entorno y luego crea una nueva función.
new_counter <- function() {
i <- 0
function() {
# do something useful, then ...
i <<- i + 1
i
}
}
La nueva función es un cierre, y su entorno es el entorno circundante. Cuando se ejecutan los cierres counter_one
y counter_two
, cada uno modifica el contador en su entorno circundante y luego devuelve el conteo actual.
counter_one <- new_counter()
counter_two <- new_counter()
counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1
f <- function(n, x0) {x <- x0; replicate(n, (function(){x <<- x+rnorm(1)})())}
plot(f(1000,0),typ="l")