<<-
es más útil junto con cierres para mantener el estado. Aquí hay una sección de un artículo mío reciente:
Un cierre es una función escrita por otra función. Los cierres se denominan así porque encierran el entorno de la función principal y pueden acceder a todas las variables y parámetros de 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 puede usar esta idea para generar una familia de funciones de poder. La función principal ( power
) crea funciones secundarias ( 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 hace posible mantener el estado en las invocaciones de funciones al permitir que una función modifique variables en el entorno de su padre. La clave para administrar variables en diferentes niveles es el operador de asignación de doble flecha <<-
. A diferencia de la asignación de flecha única habitual ( <-
) que siempre funciona en el nivel actual, el operador de flecha doble puede modificar las variables en los niveles principales.
Esto permite mantener un contador que registra cuántas veces se ha llamado a una función, como muestra el siguiente ejemplo. Cada vez que new_counter
se ejecuta, 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 envolvente. Cuando se ejecutan los cierres counter_one
y counter_two
, cada uno modifica el contador en su entorno cerrado 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