termodinámica estadístico estadistico entre enfoque diferencia cuál clásico clasico r closures local static-variables

estadistico - cuál es la diferencia entre enfoque clásico y estadístico de la termodinámica



¿En qué se diferencia local() de otros enfoques para cerrar en R? (2)

local() puede implementar un patrón de singleton; por ejemplo, el paquete snow utiliza para rastrear la instancia única de Rmpi ​​que el usuario podría crear.

getMPIcluster <- NULL setMPIcluster <- NULL local({ cl <- NULL getMPIcluster <<- function() cl setMPIcluster <<- function(new) cl <<- new })

local() también se puede usar para administrar la memoria en un script, por ejemplo, la asignación de grandes objetos intermedios necesarios para crear un objeto final en la última línea de la cláusula. Los objetos intermedios grandes están disponibles para la recolección de basura cuando se devuelve local .

El uso de una función para crear un cierre es un patrón de fábrica: el ejemplo de cuenta bancaria en la documentación Introducción a R, donde cada vez que se invoca open.account , se crea una nueva cuenta.

Como @otsaw menciona, la memoria puede implementarse usando local, por ejemplo, para cachear sitios web en un rastreador

library(XML) crawler <- local({ seen <- new.env(parent=emptyenv()) .do_crawl <- function(url, base, pattern) { if (!exists(url, seen)) { message(url) xml <- htmlTreeParse(url, useInternal=TRUE) hrefs <- unlist(getNodeSet(xml, "//a/@href")) urls <- sprintf("%s%s", base, grep(pattern, hrefs, value=TRUE)) seen[[url]] <- length(urls) for (url in urls) .do_crawl(url, base, pattern) } } .do_report <- function(url) { urls <- as.list(seen) data.frame(Url=names(urls), Links=unlist(unname(urls)), stringsAsFactors=FALSE) } list(crawl=function(base, pattern="^/.*html$") { .do_crawl(base, base, pattern) }, report=.do_report) }) crawler$crawl(favorite_url) dim(crawler$report())

(El ejemplo habitual de memoización, los números de Fibonacci, no es satisfactorio: el rango de números que no desbordan la representación numérica de R es pequeño, por lo que probablemente se utilice una tabla de búsqueda de valores calculados de manera eficiente). Interesante cómo el rastreador aquí es un singleton; podría tan fácilmente haber seguido un patrón de fábrica, por lo que un rastreador por URL base.

Ayer aprendí de Bill Venables cómo local () puede ayudar a crear funciones y variables estáticas, por ejemplo,

example <- local({ hidden.x <- "You can''t see me!" hidden.fn <- function(){ cat("/"hidden.fn()/"") } function(){ cat("You can see and call example()/n") cat("but you can''t see hidden.x/n") cat("and you can''t call ") hidden.fn() cat("/n") } })

que se comporta de la siguiente manera desde el símbolo del sistema:

> ls() [1] "example" > example() You can see and call example() but you can''t see hidden.x and you can''t call "hidden.fn()" > hidden.x Error: object ''hidden.x'' not found > hidden.fn() Error: could not find function "hidden.fn"

He visto este tipo de cosas discutidas en Variables estáticas en R donde se empleó un enfoque diferente.

¿Cuáles son los pros y los contras de estos dos métodos?


Encapsulacion

La ventaja de este estilo de programación es que es probable que los objetos ocultos no se sobrescriban con ninguna otra cosa, por lo que puede estar más seguro de que contienen lo que piensa. No serán utilizados por error, ya que no se puede acceder a ellos fácilmente. En la publicación enlazada a en la pregunta hay una variable global, count , a la que se puede acceder y sobrescribir desde cualquier lugar, por lo que si estamos depurando el código y mirando la count y vemos su cambio, no podemos estar seguros de qué parte del código tiene lo cambié En contraste, en el código de ejemplo de la pregunta tenemos mayor seguridad de que no hay ninguna otra parte del código involucrada.

Tenga en cuenta que en realidad podemos acceder a la función oculta, aunque no es tan fácil:

# run hidden.fn environment(example)$hidden.fn()

Programación orientada a objetos

También tenga en cuenta que esto está muy cerca de la programación orientada a objetos, donde example y hidden.fn son métodos y hidden.x es una propiedad. Podríamos hacerlo así para hacerlo explícito:

library(proto) p <- proto(x = "x", fn = function(.) cat('' "fn()"/n ''), example = function(.) .$fn() ) p$example() # prints "fn()"

proto no oculta x y fn pero no es tan fácil acceder a ellos por error, ya que debe usar p$x y p$fn() para acceder a ellos, lo que no es tan diferente a poder escribir e <- environment(example); e$hidden.fn() e <- environment(example); e$hidden.fn()

EDITAR:

El enfoque orientado a objetos agrega la posibilidad de herencia, por ejemplo, uno podría definir un hijo de p que actúa como p excepto que reemplaza a fn .

ch <- p$proto(fn = function(.) cat("Hello from ch/n")) # child ch$example() # prints: Hello from ch