Pregunta

Me acaba de terminar la lectura sobre de alcance en el R introducción , y soy muy curioso acerca de la asignación <<-.

El manual mostró un ejemplo (muy interesante) para <<-, que siento que comprendía. Lo que todavía me falta es el contexto de cuando esto puede ser útil.

Así que lo que me gustaría leer de usted son ejemplos (o enlaces a ejemplos) sobre cuándo el uso de <<- puede ser interesante / útil. ¿Cuáles podrían ser los peligros de su uso (se ve fácil perder el rumbo de), y algunos consejos que te pueden sentir que compartir.

¿Fue útil?

Solución

<<- es más útil en conjunción con cierres para mantener el estado. Aquí está una sección de un documento reciente de la mina:

Un cierre es una función escrita por otra función. Los cierres se llaman así porque encierran el medio ambiente de la función madre, y se puede 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 de los padres (power) crea funciona el niño (square y cube) que en realidad hacer 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 gestionar las variables en dos niveles también hace que sea posible mantener el estado a través de invocaciones de funciones al permitir una función para modificar las variables en el entorno de su padre. Clave para manejar las variables en los diferentes niveles es el doble <<- operador de asignación flecha. A diferencia de la asignación habitual sola flecha (<-) que siempre funciona en el nivel actual, el operador flecha doble puede modificar las variables de nivel superior.

Esto hace que sea posible mantener un contador que registra el número de veces una función ha sido llamados, como muestra el siguiente ejemplo. Cada vez que se ejecuta new_counter, se crea un ambiente, inicializa el contador i en este ambiente, 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 medio ambiente es el entorno envolvente. Cuando se ejecute el cierre de counter_one y counter_two, cada uno modifica el contador en su entorno envolvente y devuelve el recuento actual.

counter_one <- new_counter()
counter_two <- new_counter()

counter_one() # -> [1] 1
counter_one() # -> [1] 2
counter_two() # -> [1] 1

Otros consejos

Ayuda a pensar en <<- como equivalente a assign (si se establece el parámetro inherits en esa función a TRUE). El beneficio de assign es que le permite especificar más parámetros (por ejemplo, el medio ambiente), así que prefiero utilizar assign sobre <<- en la mayoría de los casos.

Uso de medios <<- y assign(x, value, inherits=TRUE) que "entornos del entorno suministrado encerrando se buscan hasta que la variable 'X' es encontrado." En otras palabras, será seguir adelante a través de los entornos con el fin hasta que encuentra una variable con ese nombre, y se le asignará a eso. Esto puede ser en el ámbito de una función, o en el entorno global.

Con el fin de entender lo que hacen estas funciones, es necesario entender también los entornos de investigación (por ejemplo, utilizando search).

Yo uso regularmente estas funciones cuando estoy corriendo una simulación grande y quiero guardar los resultados intermedios. Esto le permite crear el objeto fuera del alcance del bucle de función o apply dado. Eso es muy útil, especialmente si usted tiene alguna preocupación acerca de un gran bucle que termina de forma inesperada (por ejemplo, una base de datos de desconexión), en cuyo caso se podría perder todo en el proceso. Esto sería equivalente a escribir sus resultados a una base de datos o archivo durante un proceso de larga duración, excepto que está almacenando los resultados en el entorno de I en su lugar.

Mi primario de alarma con esto: tenga cuidado porque usted está ahora trabajando con variables globales, especialmente cuando se utiliza <<-. Eso significa que usted puede terminar con situaciones en las que una función se utiliza un valor de objeto del ambiente, cuando se esperaba que fuera utilizando uno que se suministra como un parámetro. Esta es una de las cosas principales que trata de programación funcionales que deben evitarse (ver efectos secundarios ). Evito este problema mediante la asignación de mis valores a unos nombres de variables únicas (usando pasta con un conjunto o parámetros únicos) que nunca se utilizan dentro de la función, pero acabo de utilizar para almacenar en caché y, en caso de que necesite para recuperarse más tarde (o hacer algo de meta -Análisis de los resultados intermedios).

Un lugar donde solía <<- estaba en interfaces gráficas de usuario simples usando Tcl / Tk. Algunos de los ejemplos iniciales tienen que - como es necesario hacer una distinción entre las variables locales y globales para statefullness. Véase, por ejemplo

 library(tcltk)
 demo(tkdensity)

que utiliza <<-. De lo contrario, estoy de acuerdo con Marek :) - una búsqueda en Google puede ayudar

.
f <- function(n, x0) {x <- x0; replicate(n, (function(){x <<- x+rnorm(1)})())}
plot(f(1000,0),typ="l")

El operador <<- también puede ser útil para Clases de referencia cuando se escribe 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 <<- comportarse de forma extraña cuando se aplica (incorrectamente) dentro de un bucle for (puede haber otros casos también). Dado el siguiente código:

fortest <- function() {
    mySum <- 0
    for (i in c(1, 2, 3)) {
        mySum <<- mySum + i
    }
    mySum
}

se podría esperar que la función devolvería la suma esperada, 6, pero en su lugar se devuelve 0, con un mySum variable global que se crea y se le asigna el valor 3. No se puede explicar completamente lo que está pasando aquí, pero sin duda el cuerpo de un bucle es no 'nivel' un nuevo ámbito de aplicación. En cambio, parece que R miradas fuera de la función fortest, no puede encontrar una variable mySum asignar a, por lo que crea uno y asigna el valor 1, la primera vez a través del bucle. En iteraciones posteriores, el RHS en la asignación debe referirse a la (sin cambios) variable de mySum interior 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 de esa iteración de i, por lo tanto, tiene el valor 3 a la salida de la función.

Espero que esto ayude a alguien - esto me dejó perplejo durante un par de horas de hoy! (Por cierto, basta con sustituir <<- con <- y las obras funcionar como se espera).

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top