Tengo el siguiente código para comprender las complejas capas del entorno:

depositor <- function() {
  balance <- 0
  function(amount) {
   balance <<- balance + amount # assign in the parent
    return(balance) 
  } 
}
deposit <- depositor()
deposit(100)
100
deposit(32)
132

¿Podría explicarme cómo funciona el código anterior en términos de entorno?

No entiendo de la línea deposit <- depositor()

¡Gracias chicos!

1
jayinbluecity 10 dic. 2016 a las 11:13
depositor devuelve una función. Esta función toma un número como entrada y recuerda y devuelve la suma acumulativa de los números recibidos hasta el momento.
 – 
Kota Mori
10 dic. 2016 a las 11:36
Esta es una función dentro de una función. El objeto de retorno de depositor() es una función, por lo que deposit(100) funciona. Mi consejo sería ignorar la fuente donde encontró esto, ya que esta no es la forma "adecuada" de R de hacer las cosas.
 – 
Roman Luštrik
10 dic. 2016 a las 11:36
Otro experimento interesante sería hacer otra función con deposit2 <- depositor(). ¿Esta función comienza desde 0 o 132?
 – 
Kota Mori
10 dic. 2016 a las 11:37
1
Por supuesto, los cierres son una forma adecuada de R. Vea la demostración de alcance.
 – 
Roland
10 dic. 2016 a las 16:23

1 respuesta

La mejor respuesta

El ojo de la cerradura para entender este ejemplo es depositor() Volverá

depositor()

function(amount) {
   balance <<- balance + amount # assign in the parent
    return(balance) 
  }
<environment: 0x8936fb0>

Esa parte es algo sencilla. El último bloque completo dentro de la función externa depositor() es la definición de una función anónima function(amount). Entonces, es esta función la que se convierte en el valor de retorno de la función externa, como lo hubiera tenido cualquier variable ordinaria. El alcance tanto de balance como de esta función anónima está limitado a la función externa, es decir, depositor, y no se puede acceder a ninguna de ellas directamente desde el exterior.

Sin embargo, la función anónima así devuelta se puede almacenar y reutilizar en el marco principal (entorno global).

 environment(fun = depositor)
# <environment: R_GlobalEnv>
 environment(fun = deposit)
# <environment: 0x8a3f5a8>
parent.env(  environment(fun = deposit) )
# <environment: R_GlobalEnv>

deposit <- depositor() almacena esta función devuelta en un depósito llamado var, y se puede acceder a ella a través de él deposit(amountvalue)

El alcance de amount todavía está limitado a la función interna. No hay forma de pasarle el valor de amount a través de la función externa ya que no está asignado en ningún otro lugar. Eso solo se puede hacer a través del proxy guardado deposit(100)


Editar: revisé mi respuesta y descubrí que había omitido la parte más interesante de este ejercicio. ¿Por qué persiste el valor de balance de una llamada a otra? es decir, ¿por qué la próxima llamada no restablece el valor del saldo a 0? Cada nueva llamada a depositor() ( ¡no depositar! ) devolverá una función con su propio entorno padre / adjunto. Aquí está la prueba: también se sugiere en un comentario anterior de @Kota Mori:

deposit<- depositor()
x<- depositor()

#following will have two different values
environment(deposit)
environment(x) 
# and they will work independently
x(100); x(20)
deposit(100);deposit(1000)

Este es el quid de closure, un tema sobre el que tengo poco que ofrecer. Una llamada a la función interna i.e., x() or deposit() no interferirá con el entorno asociado con la llamada anterior, porque no se llamará a la función principal en sí, solo se llamará a la función interna. En este caso, la función interna también actualiza el equilibrio en su entorno circundante respectivo a través de la asignación <<-, conservando así el valor de una llamada a la siguiente.


Otra cosa puede ser, ¿por qué una variable devuelta por una función no viene con un recinto similar? Es porque según la documentación de function - the value of the last evaluated expression is returned.

4
R.S. 10 dic. 2016 a las 13:57